From: Ulrich Drepper Date: Thu, 2 Jan 2003 11:01:30 +0000 (+0000) Subject: Update. X-Git-Tag: upstream/2.30~20359 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=05df18c3475157cda8126a07b5bb0f52082a0b67;p=external%2Fglibc.git Update. 2003-01-02 Ulrich Drepper * sysdeps/pthread/bits/pthreadtypes.h (pthread_cond_t): Add padding. * condvar.c: Add symbol versioning. The compatibility versions are the same as the change in the interface does not effect this implementation. * Versions [libpthread]: Add definitions for new pthread_cond_* interfaces for version GLIBC_2.3.2. --- diff --git a/linuxthreads/ChangeLog b/linuxthreads/ChangeLog index 20ee770..a667e22 100644 --- a/linuxthreads/ChangeLog +++ b/linuxthreads/ChangeLog @@ -1,3 +1,12 @@ +2003-01-02 Ulrich Drepper + + * sysdeps/pthread/bits/pthreadtypes.h (pthread_cond_t): Add padding. + * condvar.c: Add symbol versioning. The compatibility versions + are the same as the change in the interface does not effect this + implementation. + * Versions [libpthread]: Add definitions for new pthread_cond_* + interfaces for version GLIBC_2.3.2. + 2002-12-31 Ulrich Drepper * sysdeps/unix/sysv/linux/fork.h: Add libc_hidden_proto for diff --git a/linuxthreads/Versions b/linuxthreads/Versions index cf7f340..8dd40ee 100644 --- a/linuxthreads/Versions +++ b/linuxthreads/Versions @@ -156,6 +156,12 @@ libpthread { # Cancellation wrapper __nanosleep; } + GLIBC_2.3.2 { + # Changed pthread_cond_t. + pthread_cond_init; pthread_cond_destroy; + pthread_cond_wait; pthread_cond_timedwait; + pthread_cond_signal; pthread_cond_broadcast; + } GLIBC_PRIVATE { # Internal libc interface to libpthread __pthread_kill_other_threads_np; diff --git a/linuxthreads/condvar.c b/linuxthreads/condvar.c index a40ae49..6ab95b8 100644 --- a/linuxthreads/condvar.c +++ b/linuxthreads/condvar.c @@ -24,6 +24,7 @@ #include "spinlock.h" #include "queue.h" #include "restart.h" +#include int __pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) @@ -32,14 +33,26 @@ int __pthread_cond_init(pthread_cond_t *cond, cond->__c_waiting = NULL; return 0; } -strong_alias (__pthread_cond_init, pthread_cond_init) +versioned_symbol (libpthread, __pthread_cond_init, pthread_cond_init, + GLIBC_2_3_2); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_init, __old_pthread_cond_init) +compat_symbol (libpthread, __old_pthread_cond_init, pthread_cond_init, + GLIBC_2_0); +#endif int __pthread_cond_destroy(pthread_cond_t *cond) { if (cond->__c_waiting != NULL) return EBUSY; return 0; } -strong_alias (__pthread_cond_destroy, pthread_cond_destroy) +versioned_symbol (libpthread, __pthread_cond_destroy, pthread_cond_destroy, + GLIBC_2_3_2); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_destroy, __old_pthread_cond_destroy) +compat_symbol (libpthread, __old_pthread_cond_destroy, pthread_cond_destroy, + GLIBC_2_0); +#endif /* Function called by pthread_cancel to remove the thread from waiting on a condition variable queue. */ @@ -134,7 +147,13 @@ int __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) pthread_mutex_lock(mutex); return 0; } -strong_alias (__pthread_cond_wait, pthread_cond_wait) +versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait, + GLIBC_2_3_2); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_wait, __old_pthread_cond_wait) +compat_symbol (libpthread, __old_pthread_cond_wait, pthread_cond_wait, + GLIBC_2_0); +#endif static int pthread_cond_timedwait_relative(pthread_cond_t *cond, @@ -230,12 +249,19 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond, return 0; } -int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, - const struct timespec * abstime) +int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec * abstime) { /* Indirect call through pointer! */ return pthread_cond_timedwait_relative(cond, mutex, abstime); } +versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait, + GLIBC_2_3_2); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_timedwait, __old_pthread_cond_timedwait) +compat_symbol (libpthread, __old_pthread_cond_timedwait, + pthread_cond_timedwait, GLIBC_2_0); +#endif int __pthread_cond_signal(pthread_cond_t *cond) { @@ -251,7 +277,13 @@ int __pthread_cond_signal(pthread_cond_t *cond) } return 0; } -strong_alias (__pthread_cond_signal, pthread_cond_signal) +versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal, + GLIBC_2_3_2); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_signal, __old_pthread_cond_signal) +compat_symbol (libpthread, __old_pthread_cond_signal, pthread_cond_signal, + GLIBC_2_0); +#endif int __pthread_cond_broadcast(pthread_cond_t *cond) { @@ -270,7 +302,13 @@ int __pthread_cond_broadcast(pthread_cond_t *cond) } return 0; } -strong_alias (__pthread_cond_broadcast, pthread_cond_broadcast) +versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast, + GLIBC_2_3_2); +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +strong_alias (__pthread_cond_broadcast, __old_pthread_cond_broadcast) +compat_symbol (libpthread, __old_pthread_cond_broadcast, + pthread_cond_broadcast, GLIBC_2_0); +#endif int __pthread_condattr_init(pthread_condattr_t *attr) { diff --git a/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h b/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h index 3ee5c48..43d4f7d 100644 --- a/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h +++ b/linuxthreads/sysdeps/pthread/bits/pthreadtypes.h @@ -57,6 +57,8 @@ typedef struct { struct _pthread_fastlock __c_lock; /* Protect against concurrent access */ _pthread_descr __c_waiting; /* Threads waiting on this condition */ + char __padding[48 - sizeof (struct _pthread_fastlock) + - sizeof (_pthread_descr)]; } pthread_cond_t; diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 764ab23..ec44dff 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,28 @@ +2003-01-02 Ulrich Drepper + + * sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h (pthread_cond_t): + New, larger type definition. + * sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S: New condvar + implementation. + * Versions [libpthread]: Add definitions for new pthread_cond_* + interfaces for version GLIBC_2.3.2. + * pthread_cond_init.c: Update initialization for new type definition. + * Makefile (libpthread-routines): Remove pthread_cond_wait, + pthread_cond_timedwait, pthread_cond_signal, and + pthread_cond_broadcast. Add old_pthread_cond_init, + old_pthread_cond_destroy, old_pthread_cond_wait, + old_pthread_cond_timedwait, old_pthread_cond_signal, and + old_pthread_cond_broadcast. + * old_pthread_cond_broadcast.c: New file. + * old_pthread_cond_destroy.c: New file. + * old_pthread_cond_init.c: New file. + * old_pthread_cond_signal.c: New file. + * old_pthread_cond_timedwait.c: New file. + * old_pthread_cond_wait.c: New file. + * pthreadP.h: Add prototypes for the compatibility interfaces. + + * pthread_cond_destroy.c: Don't include . + 2003-01-01 Ulrich Drepper * sysdeps/unix/sysv/linux/i386/i486/lowlevelrwlock.S: Avoid diff --git a/nptl/DESIGN-condvar.txt b/nptl/DESIGN-condvar.txt index 303807b..749180e 100644 --- a/nptl/DESIGN-condvar.txt +++ b/nptl/DESIGN-condvar.txt @@ -7,49 +7,78 @@ Conditional Variable pseudocode. struct pthread_cond_t { - unsigned int lock: + unsigned int cond_lock; internal mutex - unsigned int nr_wakers: + uint64_t total_seq; - number of threads signalled to be woken up. + Total number of threads using the conditional variable. - unsigned int nr_sleepers: + uint64_t wakeup_seq; - number of threads waiting for the cv. + sequence number for next wakeup. + + uint64_t woken_seq; + + sequence number of last woken thread. } -#define ALL_THREADS (1 << (BITS_PER_LONG-1)) -cond_wait_timeout(cv, mutex, timeout): + +cleanup_handler(cv) +{ + lll_lock(cv->lock); + + ++cv->wakeup_seq; + ++cv->woken_seq; + + lll_unlock(cv->lock); +} + + +cond_timedwait(cv, mutex, timeout): { lll_lock(cv->lock); mutex_unlock(mutex); - cv->nr_sleepers++; - for (;;) { + cleanup_push + + ++cv->total_seq; + val = seq = cv->wakeup_seq; + + while (1) { + + lll_unlock(cv->lock); + + enable_async - if (cv->nr_wakers) { - cv->nr_wakers--; - break; - } - val = cv->nr_wakers; + ret = FUTEX_WAIT(cv->wakeup_seq, val, timeout); - lll_unlock(cv->lock); + restore_async - ret = FUTEX WAIT (cv->nr_wakers, val, timeout) + lll_lock(cv->lock); - lll_lock(cv->lock); + val = cv->wakeup_seq; - if (ret == TIMEOUT) - break; + if (cv->woken_seq >= seq && cv->woken_seq < val) { ret = 0; + break; + } + + if (ret == TIMEDOUT) { + ++cv->wakeup_seq; + break; + } } - if (!--cv->nr_sleepers) - cv->nr_wakers = 0; /* no memory of wakeups */ + + ++cv->woken_seq; + lll_unlock(cv->lock); + + cleanup_pop + mutex_lock(mutex); return ret; @@ -57,34 +86,24 @@ cond_wait_timeout(cv, mutex, timeout): 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; + + if (cv->total_seq > cv->wakeup_seq) { + ++cv->wakeup_seq; + FUTEX_WAKE(cv->wakeup_seq, 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; + + if (cv->total_seq > cv->wakeup_seq) { + cv->wakeup_seq = cv->total_seq; + FUTEX_WAKE(cv->wakeup_seq, ALL); } + 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/Makefile b/nptl/Makefile index f1aaf48..274b1b2 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -65,8 +65,9 @@ libpthread-routines = init events \ 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 \ + old_pthread_cond_init old_pthread_cond_destroy \ + old_pthread_cond_wait old_pthread_cond_timedwait \ + old_pthread_cond_signal old_pthread_cond_broadcast \ pthread_condattr_init pthread_condattr_destroy \ pthread_condattr_getpshared pthread_condattr_setpshared \ pthread_spin_init pthread_spin_destroy \ diff --git a/nptl/Versions b/nptl/Versions index b9de74a..26655f3 100644 --- a/nptl/Versions +++ b/nptl/Versions @@ -186,6 +186,11 @@ libpthread { } GLIBC_2.3.2 { + # Changed pthread_cond_t. + pthread_cond_init; pthread_cond_destroy; + pthread_cond_wait; pthread_cond_timedwait; + pthread_cond_signal; pthread_cond_broadcast; + # Proposed API extensions. # XXX Adjust number for final release. pthread_tryjoin_np; pthread_timedjoin_np; diff --git a/nptl/old_pthread_cond_broadcast.c b/nptl/old_pthread_cond_broadcast.c new file mode 100644 index 0000000..9d63af9 --- /dev/null +++ b/nptl/old_pthread_cond_broadcast.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 , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include "pthreadP.h" +#include + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +int +__old_pthread_cond_broadcast (cond) + pthread_cond_t *cond; +{ + pthread_cond_t **realp = (pthread_cond_t **) cond; + + if (*realp == NULL) + { + *realp = (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); + if (*realp == NULL) + return ENOMEM; + + **realp = (struct pthread_cond_t) PTHREAD_COND_INITIALIZER; + } + + return __pthread_cond_broadcast (*realp); +} +compat_symbol (libpthread, __old_pthread_cond_broadcast, + pthread_cond_broadcast, GLIBC_2_0); +#endif diff --git a/nptl/old_pthread_cond_destroy.c b/nptl/old_pthread_cond_destroy.c new file mode 100644 index 0000000..9afe7d3 --- /dev/null +++ b/nptl/old_pthread_cond_destroy.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 , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include "pthreadP.h" +#include + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +int +__old_pthread_cond_destroy (cond) + pthread_cond_t *cond; +{ + /* Free the memory which was eventually allocated. */ + free (*(void **) cond); + + return 0; +} +compat_symbol (libpthread, __old_pthread_cond_destroy, pthread_cond_destroy, + GLIBC_2_0); +#endif diff --git a/nptl/old_pthread_cond_init.c b/nptl/old_pthread_cond_init.c new file mode 100644 index 0000000..70275d9 --- /dev/null +++ b/nptl/old_pthread_cond_init.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 , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with 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 + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +int +__old_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. */ + + /* The type of the first argument is actually that of the old, too + small pthread_cond_t. We use only the first word of it, as a + pointer. */ + *((void **) cond) = NULL; + + return 0; +} +compat_symbol (libpthread, __old_pthread_cond_init, pthread_cond_init, + GLIBC_2_0); +#endif diff --git a/nptl/old_pthread_cond_signal.c b/nptl/old_pthread_cond_signal.c new file mode 100644 index 0000000..467812e --- /dev/null +++ b/nptl/old_pthread_cond_signal.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 , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include "pthreadP.h" +#include + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +int +__old_pthread_cond_signal (cond) + pthread_cond_t *cond; +{ + pthread_cond_t **realp = (pthread_cond_t **) cond; + + if (*realp == NULL) + { + *realp = (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); + if (*realp == NULL) + return ENOMEM; + + **realp = (struct pthread_cond_t) PTHREAD_COND_INITIALIZER; + } + + return __pthread_cond_signal (*realp); +} +compat_symbol (libpthread, __old_pthread_cond_signal, pthread_cond_signal, + GLIBC_2_0); +#endif diff --git a/nptl/old_pthread_cond_timedwait.c b/nptl/old_pthread_cond_timedwait.c new file mode 100644 index 0000000..6f84434 --- /dev/null +++ b/nptl/old_pthread_cond_timedwait.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 , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include "pthreadP.h" +#include + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +int +__old_pthread_cond_timedwait (cond, mutex, abstime) + pthread_cond_t *cond; + pthread_mutex_t *mutex; + const struct timespec *abstime; +{ + pthread_cond_t **realp = (pthread_cond_t **) cond; + + if (*realp == NULL) + { + *realp = (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); + if (*realp == NULL) + return ENOMEM; + + **realp = (struct pthread_cond_t) PTHREAD_COND_INITIALIZER; + } + + return __pthread_cond_timedwait (*realp, mutex, abstime); +} +compat_symbol (libpthread, __old_pthread_cond_timedwait, + pthread_cond_timedwait, GLIBC_2_0); +#endif diff --git a/nptl/old_pthread_cond_wait.c b/nptl/old_pthread_cond_wait.c new file mode 100644 index 0000000..4a7282f --- /dev/null +++ b/nptl/old_pthread_cond_wait.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 , 2002. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include "pthreadP.h" +#include + + +#if SHLIB_COMPAT(libpthread, GLIBC_2_0, GLIBC_2_3_2) +int +__old_pthread_cond_wait (cond, mutex) + pthread_cond_t *cond; + pthread_mutex_t *mutex; +{ + pthread_cond_t **realp = (pthread_cond_t **) cond; + + if (*realp == NULL) + { + *realp = (pthread_cond_t *) malloc (sizeof (pthread_cond_t)); + if (*realp == NULL) + return ENOMEM; + + **realp = (struct pthread_cond_t) PTHREAD_COND_INITIALIZER; + } + + return __pthread_cond_wait (*realp, mutex); +} +compat_symbol (libpthread, __old_pthread_cond_wait, pthread_cond_wait, + GLIBC_2_0); +#endif diff --git a/nptl/pthreadP.h b/nptl/pthreadP.h index eb5c6d4..e4a9013 100644 --- a/nptl/pthreadP.h +++ b/nptl/pthreadP.h @@ -315,6 +315,17 @@ extern int __pthread_enable_asynccancel (void) attribute_hidden; extern void __pthread_disable_asynccancel (int oldtype) internal_function attribute_hidden; +extern int __old_pthread_cond_broadcast (pthread_cond_t *cond); +extern int __old_pthread_cond_destroy (pthread_cond_t *cond); +extern int __old_pthread_cond_init (pthread_cond_t *cond, + const pthread_condattr_t *cond_attr); +extern int __old_pthread_cond_signal (pthread_cond_t *cond); +extern int __old_pthread_cond_timedwait (pthread_cond_t *cond, + pthread_mutex_t *mutex, + const struct timespec *abstime); +extern int __old_pthread_cond_wait (pthread_cond_t *cond, + pthread_mutex_t *mutex); + /* The two functions are in libc.so and not exported. */ extern int __libc_enable_asynccancel (void) attribute_hidden; extern void __libc_disable_asynccancel (int oldtype) diff --git a/nptl/pthread_cond_destroy.c b/nptl/pthread_cond_destroy.c index 750cd0c..130cb21 100644 --- a/nptl/pthread_cond_destroy.c +++ b/nptl/pthread_cond_destroy.c @@ -17,7 +17,6 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ -#include #include "pthreadP.h" diff --git a/nptl/pthread_cond_init.c b/nptl/pthread_cond_init.c index 2b782c2..cd762f2 100644 --- a/nptl/pthread_cond_init.c +++ b/nptl/pthread_cond_init.c @@ -30,8 +30,9 @@ __pthread_cond_init (cond, cond_attr) variables are always usable in multiple processes. */ cond->__data.__lock = LLL_MUTEX_LOCK_INITIALIZER; - cond->__data.__nr_wakers = 0; - cond->__data.__nr_sleepers = 0; + cond->__data.__total_seq = 0; + cond->__data.__wakeup_seq = 0; + cond->__data.__woken_seq = 0; return 0; } diff --git a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h index dbd477c..97b94a3 100644 --- a/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h +++ b/nptl/sysdeps/unix/sysv/linux/i386/bits/pthreadtypes.h @@ -23,7 +23,8 @@ #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_COND_T 48 +#define __SIZEOF_PTHREAD_COND_COMPAT_T 12 #define __SIZEOF_PTHREAD_CONDATTR_T 4 #define __SIZEOF_PTHREAD_RWLOCK_T 32 #define __SIZEOF_PTHREAD_RWLOCKATTR_T 8 @@ -74,11 +75,12 @@ typedef union struct { int __lock; - unsigned int __nr_wakers; - unsigned int __nr_sleepers; + unsigned long long int __total_seq; + unsigned long long int __wakeup_seq; + unsigned long long int __woken_seq; } __data; char __size[__SIZEOF_PTHREAD_COND_T]; - long int __align; + long long int __align; } pthread_cond_t; typedef union diff --git a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S index e8c8d5d..1cbf2ea 100644 --- a/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S +++ b/nptl/sysdeps/unix/sysv/linux/i386/i486/lowlevelcond.S @@ -18,8 +18,7 @@ 02111-1307 USA. */ #include - - .text +#include #ifdef UP # define LOCK @@ -32,248 +31,622 @@ #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 +#define cond_lock 0 +#define total_seq 4 +#define wakeup_seq 12 +#define woken_seq 20 + + .text - .global __lll_cond_wait - .type __lll_cond_wait,@function - .hidden __lll_cond_wait .align 16 -__lll_cond_wait: + .type condvar_cleanup, @function +condvar_cleanup: + pushl %ebx + movl 4(%esp), %ebx +#if cond_lock != 0 + addl $cond_lock, %ebx +#endif + + /* Get internal lock. */ + movl $1, %eax + LOCK +#if cond_lock == 0 + xaddl %eax, (%ebx) +#else + xaddl %eax, cond_lock(%ebx) +#endif + testl %eax, %eax + je 1f + +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + +1: addl $1, wakeup_seq(%ebx) + adcl $0, wakeup_seq+4(%ebx) + + addl $1, woken_seq(%ebx) + adcl $0, woken_seq+4(%ebx) + + LOCK + decl (%ebx) + je 2f +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + +2: popl %ebx + ret + .size condvar_cleanup, .-condvar_cleanup + + +/* int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) */ + .globl __pthread_cond_wait + .type __pthread_cond_wait, @function + .align 16 +__pthread_cond_wait: + + pushl %edi pushl %esi pushl %ebx xorl %esi, %esi + movl 16(%esp), %ebx +#if cond_lock != 0 + addl $cond_lock, %ebx +#endif - leal cond_nr_wakers(%eax), %ebx - -4: movl (%ebx), %edx - testl %edx, %edx + /* Get internal lock. */ + movl $1, %eax + LOCK +#if cond_lock == 0 + xaddl %eax, (%ebx) +#else + xaddl %eax, cond_lock(%ebx) +#endif + testl %eax, %eax jne 1f - LOCK - decl cond_lock-cond_nr_wakers(%ebx) - jne 2f + /* Unlock the mutex. */ +2: pushl 20(%esp) + call __pthread_mutex_unlock_internal + + addl $1, total_seq(%ebx) + adcl $0, total_seq+4(%ebx) -3: xorl %ecx, %ecx + /* Install cancellation handler. */ +#ifdef PIC + call __i686.get_pc_thunk.cx + addl $_GLOBAL_OFFSET_TABLE_, %ecx + leal condvar_cleanup@GOTOFF(%ecx), %eax +#else + leal condvar_cleanup, %eax +#endif + subl $24, %esp + leal 12(%esp), %edx + movl %ebx, 8(%esp) + movl %eax, 4(%esp) + movl %edx, (%esp) + call _GI_pthread_cleanup_push + + /* Get and store current wakeup_seq value. */ + movl wakeup_seq(%ebx), %edi + movl wakeup_seq+4(%ebx), %edx + movl %edi, (%esp) + movl %edx, 4(%esp) + + /* Unlock. */ +8: LOCK +#if cond_lock == 0 + decl (%ebx) +#else + decl cond_lock(%ebx) +#endif + jne 3f + +4: call __pthread_enable_asynccancel + movl %eax, (%esp) + + movl %esi, %ecx /* movl $FUTEX_WAIT, %ecx */ + movl %edi, %edx + addl $wakeup_seq-cond_lock, %ebx movl $SYS_futex, %eax ENTER_KERNEL + subl $wakeup_seq-cond_lock, %ebx + + call __pthread_disable_asynccancel + /* Lock. */ movl $1, %eax LOCK - xaddl %eax, cond_lock-cond_nr_wakers(%ebx) +#if cond_lock == 0 + xaddl %eax, (%ebx) +#else + xaddl %eax, cond_lock(%ebx) +#endif testl %eax, %eax - je 4b + jne 5f - leal cond_lock-cond_nr_wakers(%ebx), %ecx - /* Preserves %ebx, %edx, %edi, %esi. */ - call __lll_mutex_lock_wait - jmp 4b +6: movl woken_seq(%ebx), %eax + movl woken_seq+4(%ebx), %ecx + + movl wakeup_seq(%ebx), %edi + movl wakeup_seq+4(%ebx), %edx -1: decl (%ebx) + cmpl 4(%esp), %ecx + ja 7f + jb 8b + cmpl (%esp), %eax + jb 8b + +7: cmpl %ecx, %edx + ja 9f + jb 8b + cmp %eax, %edi + jna 8b + +9: addl $1, woken_seq(%ebx) + adcl $0, woken_seq+4(%ebx) + + LOCK +#if cond_lock == 0 + decl (%ebx) +#else + decl cond_lock(%ebx) +#endif + jne 10f + + /* Remove cancellation handler. */ +11: leal 12(%esp), %edx + movl $0, 4(%esp) + movl %edx, (%esp) + call _GI_pthread_cleanup_pop + + movl 48(%esp), %eax + movl %eax, (%esp) + call __pthread_mutex_lock_internal + addl $28, %esp popl %ebx popl %esi + popl %edi + + /* We return the result of the mutex_lock operation. */ ret -2: leal cond_lock-cond_nr_wakers(%ebx), %eax - /* Preserves %ebx, %ecx, %edx, %edi, %esi. */ + /* Initial locking failed. */ +1: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires waekup. */ +3: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 4b + + /* Locking in loop failed. */ +5: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 6b + + /* Unlock after loop requires waekup. */ +10: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif call __lll_mutex_unlock_wake - jmp 3b - .size __lll_cond_wait,.-__lll_cond_wait + jmp 11b + .size __pthread_cond_wait, .-__pthread_cond_wait +versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait, + GLIBC_2_3_2) - .global __lll_cond_timedwait - .type __lll_cond_timedwait,@function - .hidden __lll_cond_timedwait +/* int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime) */ + .globl __pthread_cond_timedwait + .type __pthread_cond_timedwait, @function .align 16 -__lll_cond_timedwait: - /* Check for a valid timeout value. */ - cmpl $1000000000, 4(%edx) - jae 1f +__pthread_cond_timedwait: pushl %ebp pushl %edi pushl %esi pushl %ebx - /* Stack frame for the timespec and timeval structs. */ - subl $8, %esp + movl 20(%esp), %ebx + movl 28(%esp), %ebp +#if cond_lock != 0 + addl $cond_lock, %ebx +#endif - leal cond_nr_wakers(%eax), %ebp /* cond */ - movl %edx, %edi /* timeout */ + /* Get internal lock. */ + movl $1, %eax + LOCK +#if cond_lock == 0 + xaddl %eax, (%ebx) +#else + xaddl %eax, cond_lock(%ebx) +#endif + testl %eax, %eax + jne 1f -9: movl (%ebp), %esi - testl %esi, %esi - jne 5f + /* Unlock the mutex. */ +2: pushl 24(%esp) + call __pthread_mutex_unlock_internal - LOCK - decl cond_lock-cond_nr_wakers(%ebp) - jne 6f + addl $1, total_seq(%ebx) + adcl $0, total_seq+4(%ebx) + + /* Install cancellation handler. */ +#ifdef PIC + call __i686.get_pc_thunk.cx + addl $_GLOBAL_OFFSET_TABLE_, %ecx + leal condvar_cleanup@GOTOFF(%ecx), %eax +#else + leal condvar_cleanup, %eax +#endif + subl $32, %esp + leal 16(%esp), %edx + movl %ebx, 8(%esp) + movl %eax, 4(%esp) + movl %edx, (%esp) + call _GI_pthread_cleanup_push + + /* Get and store current wakeup_seq value. */ + movl wakeup_seq(%ebx), %edi + movl wakeup_seq+4(%ebx), %edx + movl %edi, 12(%esp) + movl %edx, 16(%esp) + + /* Unlock. */ +8: LOCK +#if cond_lock == 0 + decl (%ebx) +#else + decl cond_lock(%ebx) +#endif + jne 3f + +4: call __pthread_enable_asynccancel + movl %eax, (%esp) - /* Get current time. */ -7: movl %esp, %ebx + /* Get the current time. */ + movl %ebx, %edx + leal 4(%esp), %ebx xorl %ecx, %ecx movl $SYS_gettimeofday, %eax ENTER_KERNEL + movl %edx, %ebx /* Compute relative timeout. */ - movl 4(%esp), %eax + movl 8(%esp), %eax movl $1000, %edx mul %edx /* Milli seconds to nano seconds. */ - movl (%edi), %ecx - movl 4(%edi), %edx - subl (%esp), %ecx + movl (%ebp), %ecx + movl 4(%ebp), %edx + subl 4(%esp), %ecx subl %eax, %edx - jns 3f + jns 12f addl $1000000000, %edx decl %ecx -3: testl %ecx, %ecx - js 4f /* Time is already up. */ +12: testl %ecx, %ecx + js 13f - movl %ecx, (%esp) /* Store relative timeout. */ - movl %edx, 4(%esp) - movl %esi, %edx - movl %esp, %esi + /* Store relative timeout. */ + movl %ecx, 4(%esp) + movl %edx, 8(%esp) + leal 4(%esp), %esi xorl %ecx, %ecx /* movl $FUTEX_WAIT, %ecx */ - movl %ebp, %ebx + movl %edi, %edx + addl $wakeup_seq-cond_lock, %ebx movl $SYS_futex, %eax ENTER_KERNEL + subl $wakeup_seq-cond_lock, %ebx + movl %eax, %esi - movl %eax, %edx + call __pthread_disable_asynccancel + /* Lock. */ movl $1, %eax LOCK - xaddl %eax, cond_lock-cond_nr_wakers(%ebp) +#if cond_lock == 0 + xaddl %eax, (%ebx) +#else + xaddl %eax, cond_lock(%ebx) +#endif testl %eax, %eax - jne 8f + jne 5f + +6: movl woken_seq(%ebx), %eax + movl woken_seq+4(%ebx), %ecx + + movl wakeup_seq(%ebx), %edi + movl wakeup_seq+4(%ebx), %edx + + cmpl 16(%esp), %ecx + ja 7f + jb 15f + cmpl 12(%esp), %eax + jb 15f + +7: cmpl %ecx, %edx + ja 9f + jb 15f + cmp %eax, %edi + ja 9f + +15: cmpl $-ETIMEDOUT, %esi + jne 8b + +13: addl $1, wakeup_seq(%ebx) + adcl $0, wakeup_seq+4(%ebx) + movl $ETIMEDOUT, %esi + jmp 14f + +9: xorl %esi, %esi +14: addl $1, woken_seq(%ebx) + adcl $0, woken_seq+4(%ebx) + + LOCK +#if cond_lock == 0 + decl (%ebx) +#else + decl cond_lock(%ebx) +#endif + jne 10f - cmpl $-ETIMEDOUT, %edx - jne 9b + /* Remove cancellation handler. */ +11: leal 20(%esp), %edx + movl $0, 4(%esp) + movl %edx, (%esp) + call _GI_pthread_cleanup_pop -4: movl $ETIMEDOUT, %eax - jmp 2f + movl 60(%esp), %ecx + movl %ecx, (%esp) + call __pthread_mutex_lock_internal + addl $36, %esp -5: decl (%ebp) - xorl %eax, %eax + movl %esi, %eax -2: addl $8, %esp popl %ebx popl %esi popl %edi popl %ebp + + /* We return the result of the mutex_lock operation. */ ret -6: leal cond_lock-cond_nr_wakers(%ebp), %eax - /* Preserves %ebx, %ecx, %edx, %edi, %esi. */ + /* Initial locking failed. */ +1: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif + call __lll_mutex_lock_wait + jmp 2b + + /* Unlock in loop requires waekup. */ +3: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif call __lll_mutex_unlock_wake - jmp 7b + jmp 4b -8: leal cond_lock-cond_nr_wakers(%ebp), %ecx - /* Preserves %ebx, %edx, %edi, %esi. */ + /* Locking in loop failed. */ +5: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif call __lll_mutex_lock_wait - jmp 5b + jmp 6b -1: movl $EINVAL, %eax - ret - .size __lll_cond_timedwait,.-__lll_cond_timedwait + /* Unlock after loop requires waekup. */ +10: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 11b + .size __pthread_cond_timedwait, .-__pthread_cond_timedwait +versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait, + GLIBC_2_3_2) - .global __lll_cond_wake - .type __lll_cond_wake,@function - .hidden __lll_cond_wake + /* int pthread_cond_signal (pthread_cond_t *cond) */ + .globl __pthread_cond_signal + .type __pthread_cond_signal, @function .align 16 -__lll_cond_wake: +__pthread_cond_signal: + pushl %esi pushl %ebx +#if cond_lock != 0 + addl $cond_lock, %ebx +#endif - movl %eax, %ebx + movl 12(%esp), %ebx + /* Get internal lock. */ movl $1, %eax LOCK - xaddl %eax, (%ebx) + xaddl %eax, cond_lock(%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 +2: movl total_seq+4(%ebx), %eax + movl total_seq(%ebx), %ecx + cmpl wakeup_seq+4(%ebx), %eax + ja 3f + jb 4f + cmpl wakeup_seq(%ebx), %ecx + jbe 4f + + /* Bump the wakeup number. */ +3: addl $1, wakeup_seq(%ebx) + adcl $0, wakeup_seq+4(%ebx) + + /* Wake up one thread. */ + addl $wakeup_seq-cond_lock, %ebx + movl $FUTEX_WAKE, %ecx xorl %esi, %esi - movl %ecx, %edx /* movl $1, %edx */ movl $SYS_futex, %eax + movl %ecx, %edx /* movl $1, %edx */ ENTER_KERNEL -3: LOCK - decl cond_lock-cond_nr_wakers(%ebx) - je,pt 4f + subl $wakeup_seq-cond_lock, %ebx - leal cond_lock-cond_nr_wakers(%ebx), %eax - call __lll_mutex_unlock_wake + /* Unlock. */ +4: LOCK + decl cond_lock(%ebx) + jne 5f -4: popl %ebx +6: xorl %eax, %eax + popl %ebx popl %esi ret -1: movl %ebx, %ecx + /* Initial locking failed. */ +1: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif call __lll_mutex_lock_wait jmp 2b -5: movl $0x80000000, (%ebx) + /* Unlock in loop requires waekup. */ +5: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake jmp 6b - .size __lll_cond_wake,.-__lll_cond_wake + .size __pthread_cond_signal, .-__pthread_cond_signal +versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal, + GLIBC_2_3_2) - .global __lll_cond_broadcast - .type __lll_cond_broadcast,@function - .hidden __lll_cond_broadcast + /* int pthread_cond_broadcast (pthread_cond_t *cond) */ + .globl __pthread_cond_broadcast + .type __pthread_cond_broadcast, @function .align 16 -__lll_cond_broadcast: +__pthread_cond_broadcast: + pushl %esi pushl %ebx - movl %eax, %ebx - movl $0x8000000, %edx + movl 12(%esp), %ebx +#if cond_lock != 0 + addl $cond_lock, %ebx +#endif + /* Get internal lock. */ movl $1, %eax LOCK - xaddl %eax, (%ebx) + xaddl %eax, cond_lock(%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 +2: movl total_seq+4(%ebx), %eax + movl total_seq(%ebx), %ecx + cmpl wakeup_seq+4(%ebx), %eax + ja 3f + jb 4f + cmpl wakeup_seq(%ebx), %ecx + jna 4f + + /* Case all currently waiting threads to wake up. */ +3: movl %ecx, wakeup_seq(%ebx) + movl %eax, wakeup_seq+4(%ebx) + + /* Wake up all threads. */ + addl $wakeup_seq-cond_lock, %ebx + movl $FUTEX_WAKE, %ecx xorl %esi, %esi movl $SYS_futex, %eax + movl $0x7fffffff, %edx ENTER_KERNEL -3: LOCK - decl cond_lock-cond_nr_wakers(%ebx) - je,pt 4f + subl $wakeup_seq-cond_lock, %ebx - leal cond_lock-cond_nr_wakers(%ebx), %eax - call __lll_mutex_unlock_wake + /* Unlock. */ +4: LOCK + decl cond_lock(%ebx) + jne 5f -4: popl %ebx +6: xorl %eax, %eax + popl %ebx popl %esi ret -1: movl %ebx, %ecx + /* Initial locking failed. */ +1: +#if cond_lock == 0 + movl %ebx, %ecx +#else + leal cond_lock(%ebx), %ecx +#endif call __lll_mutex_lock_wait jmp 2b - .size __lll_cond_broadcast,.-__lll_cond_broadcast + + /* Unlock in loop requires waekup. */ +5: +#if cond_lock == 0 + movl %ebx, %eax +#else + leal cond_lock(%ebx), %eax +#endif + call __lll_mutex_unlock_wake + jmp 6b + .size __pthread_cond_broadcast, .-__pthread_cond_broadcast +versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast, + GLIBC_2_3_2) + + +#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