r5497 - in glibc-package/trunk/debian: . patches patches/hurd-i386
Author: sthibault
Date: 2013-02-24 18:16:00 +0000 (Sun, 24 Feb 2013)
New Revision: 5497
Added:
glibc-package/trunk/debian/patches/hurd-i386/libpthread_cancellation.diff
glibc-package/trunk/debian/patches/hurd-i386/libpthread_hurd_cond_timedwait.diff
Modified:
glibc-package/trunk/debian/changelog
glibc-package/trunk/debian/libc0.3.symbols.hurd-i386
glibc-package/trunk/debian/patches/series
Log:
* patches/hurd-i386/libpthread_cancellation.diff: New patch, fixes
cancellations.
* patches/hurd-i386/libpthread_hurd_cond_timedwait.diff: New patch, introduces
pthread_hurd_cond_timedwait_np needed to fix select with zero timeout in
Hurd servers.
Modified: glibc-package/trunk/debian/changelog
===================================================================
--- glibc-package/trunk/debian/changelog 2013-02-24 16:44:46 UTC (rev 5496)
+++ glibc-package/trunk/debian/changelog 2013-02-24 18:16:00 UTC (rev 5497)
@@ -9,6 +9,11 @@
version to fix stdio thread-safety.
* patches/hurd-i386/tg-pie-sbrk.diff: Fix sbrk() use in PIE binaries (e.g.
libgc, perl).
+ * patches/hurd-i386/libpthread_cancellation.diff: New patch, fixes
+ cancellations.
+ * patches/hurd-i386/libpthread_hurd_cond_timedwait.diff: New patch, introduces
+ pthread_hurd_cond_timedwait_np needed to fix select with zero timeout in
+ Hurd servers.
[ Adam Conrad ]
* debian/testsuite-checking/compare.sh: Disable failing the build on test
Modified: glibc-package/trunk/debian/libc0.3.symbols.hurd-i386
===================================================================
--- glibc-package/trunk/debian/libc0.3.symbols.hurd-i386 2013-02-24 16:44:46 UTC (rev 5496)
+++ glibc-package/trunk/debian/libc0.3.symbols.hurd-i386 2013-02-24 18:16:00 UTC (rev 5497)
@@ -944,4 +944,5 @@
libpthread.so.0.3 #PACKAGE# #MINVER#
#include "symbols.wildcards"
*@GLIBC_2.13_DEBIAN_38 2.13-38~
+ *@GLIBC_2.13_DEBIAN_39 2.13-39~
*@GLIBC_2.2.6 2.13-38~
Added: glibc-package/trunk/debian/patches/hurd-i386/libpthread_cancellation.diff
===================================================================
--- glibc-package/trunk/debian/patches/hurd-i386/libpthread_cancellation.diff (rev 0)
+++ glibc-package/trunk/debian/patches/hurd-i386/libpthread_cancellation.diff 2013-02-24 18:16:00 UTC (rev 5497)
@@ -0,0 +1,863 @@
+commit 5ab516af0779a7fd74ad893c7c67960df6ede065
+Author: Richard Braun <rbraun@sceen.net>
+Date: Sun Feb 3 16:06:51 2013 +0100
+
+ Fix pthread timeout handling and cancellation issues
+
+ This patch solves two issues. The first one is cancellation handling
+ when a cancellation request is sent before reaching a cancellation
+ point (namely, pthread_cond_{timed,}wait). Cancellation is implemented
+ by pushing an appropriate cleanup handler and switching to
+ PTHREAD_CANCEL_ASYNCHRONOUS type. The main problem is that it doesn't
+ handle pending requests, only a cancellation that occurs while blocking.
+ Other problems occur when trying to correctly handle a timeout and a
+ cancellation request through the cleanup routine.
+
+ The other issue is correctly handling timeouts. This problem was already
+ well known, as explained by the following comment :
+
+ "FIXME: What do we do if we get a wakeup message before we disconnect
+ ourself? It may remain until the next time we block."
+
+ In addition, the prevp thread member is inconsistently used. It is
+ sometimes accessed while protected by the appropriate queue lock to
+ determine whether a thread is still queued, while at times, threads
+ are unqueued without holding a lock, as in pthread_cond_broadcast :
+
+ /* We can safely walk the list of waiting threads without holding
+ the lock since it is now decoupled from the condition. */
+ __pthread_dequeuing_iterate (wakeup, wakeup)
+ __pthread_wakeup (wakeup);
+
+ This is the root cause that triggers some assertion failures.
+
+ The solution brought by this patch is to consistently use the prevp link
+ to determine if both a thread has been unqueued and if a wakeup message
+ has been sent (both are needed to wake up a thread). A thread unblocked
+ because of a timeout can now accurately determine if it needs to drain
+ its message queue. A direct improvement is that the message queue size
+ can be limited to one message, and wakeups are guaranteed to be
+ non-blocking, which allows safely calling __pthread_wakeup from critical
+ sections.
+
+ As it now affects the cleanup cancellation routine of
+ __pthread_cond_timedwait_internal, cancellation is reworked as well.
+ Cancellation type is forced to PTHREAD_CANCEL_DEFERRED during the call,
+ and actually checked on both entry and return. A hook is set by the
+ blocking thread so that the waker doesn't need to know about the call
+ implementation. Cancellation members are now protected with a mutex for
+ truely safe access.
+
+ * pthread/pt-alloc.c (initialize_pthread): Initialize the new `cancel_lock',
+ `cancel_hook' and `cancel_hook_args' fields.
+ * pthread/pt-cancel.c (pthread_cancel): Rework cancellation handling.
+ * pthread/pt-internal.h (struct __pthread): Add `cancel_lock', `cancel_hook'
+ and `cancel_hook_args' fields.
+ (__pthread_dequeue): Assert thread->prevp isn't NULL.
+ * pthread/pt-join.c (pthread_join): Describe how the cancellation point is
+ implemented.
+ * pthread/pt-setcancelstate.c (__pthread_setcancelstate): Lock the given
+ thread cancellation lock when switching state.
+ * pthread/pt-setcanceltype.c (__pthread_setcanceltype): Likewise for
+ cancellation type.
+ * pthread/pt-testcancel.c (pthread_testcancel): Likewise for pending
+ cancellations.
+ * sysdeps/generic/pt-cond-brdcast.c (__pthread_cond_broadcast): Dequeue
+ and wake up threads with condition locked.
+ * sysdeps/generic/pt-cond-signal.c (cond_signal): Remove function, move
+ implementation to ...
+ (__pthread_cond_signal): ... this function. Remove unused `unblocked'
+ variable.
+ * sysdeps/generic/pt-cond-timedwait.c (struct cancel_ctx): New structure.
+ (cancel_hook): New static function.
+ (__pthread_cond_timedwait_internal): Fix cancellation and timeout handling.
+ * sysdeps/generic/pt-mutex-timedlock.c
+ (__pthread_mutex_timedlock_internal): Fix timeout handling.
+ * sysdeps/generic/pt-rwlock-timedrdlock.c
+ (__pthread_rwlock_timedrdlock_internal): Likewise.
+ * sysdeps/generic/pt-rwlock-timedwrlock.c
+ (__pthread_rwlock_timedwrlock_internal): Likewise.
+ * sysdeps/generic/pt-rwlock-unlock.c (pthread_rwlock_unlock): Dequeue and
+ wake up threads with rwlock internal lock held.
+ * sysdeps/generic/sem-timedwait.c (__sem_timedwait_internal): Fix timeout
+ handling.
+ * sysdeps/mach/hurd/pt-docancel.c (__pthread_do_cancel): Unlock the given
+ thread cancellation lock.
+ * sysdeps/mach/pt-thread-alloc.c (create_wakeupmsg): Limit the message
+ queue size of the wakeup port to 1.
+ * sysdeps/mach/pt-wakeup.c (__pthread_wakeup): Call __mach_msg in a
+ non-blocking way.
+
+diff --git a/libpthread/pthread/pt-alloc.c b/libpthread/pthread/pt-alloc.c
+index 6af2da9..89fca8a 100644
+--- a/libpthread/pthread/pt-alloc.c
++++ b/libpthread/pthread/pt-alloc.c
+@@ -55,6 +55,9 @@ initialize_pthread (struct __pthread *new, int recycling)
+ if (err)
+ return err;
+
++ new->cancel_lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
++ new->cancel_hook = NULL;
++ new->cancel_hook_arg = NULL;
+ new->cancel_state = PTHREAD_CANCEL_ENABLE;
+ new->cancel_type = PTHREAD_CANCEL_DEFERRED;
+ new->cancel_pending = 0;
+diff --git a/libpthread/pthread/pt-cancel.c b/libpthread/pthread/pt-cancel.c
+index d19c557..96c77f7 100644
+--- a/libpthread/pthread/pt-cancel.c
++++ b/libpthread/pthread/pt-cancel.c
+@@ -31,10 +31,33 @@ pthread_cancel (pthread_t t)
+ if (! p)
+ return ESRCH;
+
++ __pthread_mutex_lock (&p->cancel_lock);
++ if (p->cancel_pending)
++ {
++ __pthread_mutex_unlock (&p->cancel_lock);
++ return 0;
++ }
++
+ p->cancel_pending = 1;
+- if (p->cancel_state == PTHREAD_CANCEL_ENABLE
+- && p->cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS)
++
++ if (p->cancel_state != PTHREAD_CANCEL_ENABLE)
++ {
++ __pthread_mutex_unlock (&p->cancel_lock);
++ return 0;
++ }
++
++ if (p->cancel_type == PTHREAD_CANCEL_ASYNCHRONOUS)
++ /* CANCEL_LOCK is unlocked by this call. */
+ err = __pthread_do_cancel (p);
++ else
++ {
++ if (p->cancel_hook != NULL)
++ /* Thread blocking on a cancellation point. Invoke hook to unblock.
++ See __pthread_cond_timedwait_internal. */
++ p->cancel_hook (p->cancel_hook_arg);
++
++ __pthread_mutex_unlock (&p->cancel_lock);
++ }
+
+ return err;
+ }
+diff --git a/libpthread/pthread/pt-internal.h b/libpthread/pthread/pt-internal.h
+index 291baf5..aeac009 100644
+--- a/libpthread/pthread/pt-internal.h
++++ b/libpthread/pthread/pt-internal.h
+@@ -73,6 +73,11 @@ struct __pthread
+ pthread_t thread;
+
+ /* Cancellation. */
++ pthread_mutex_t cancel_lock; /* Protect cancel_xxx members. */
++ void (*cancel_hook)(void *); /* Called to unblock a thread blocking
++ in a cancellation point (namely,
++ __pthread_cond_timedwait_internal). */
++ void *cancel_hook_arg;
+ int cancel_state;
+ int cancel_type;
+ int cancel_pending;
+@@ -107,6 +112,8 @@ struct __pthread
+ tcbhead_t *tcb;
+ #endif /* ENABLE_TLS */
+
++ /* Queue links. Since PREVP is used to determine if a thread has been
++ awaken, it must be protected by the queue lock. */
+ struct __pthread *next, **prevp;
+ };
+
+@@ -128,6 +135,7 @@ static inline void
+ __pthread_dequeue (struct __pthread *thread)
+ {
+ assert (thread);
++ assert (thread->prevp);
+
+ if (thread->next)
+ thread->next->prevp = thread->prevp;
+@@ -264,7 +272,8 @@ extern error_t __pthread_timedblock (struct __pthread *__restrict thread,
+ extern void __pthread_wakeup (struct __pthread *thread);
+
+
+-/* Perform a cancelation. */
++/* Perform a cancelation. The CANCEL_LOCK member of the given thread must
++ be locked before calling this function, which must unlock it. */
+ extern int __pthread_do_cancel (struct __pthread *thread);
+
+
+diff --git a/libpthread/pthread/pt-join.c b/libpthread/pthread/pt-join.c
+index 153058b..8bd2c6c 100644
+--- a/libpthread/pthread/pt-join.c
++++ b/libpthread/pthread/pt-join.c
+@@ -40,6 +40,8 @@ pthread_join (pthread_t thread, void **status)
+ pthread_cleanup_push ((void (*)(void *)) __pthread_mutex_unlock,
+ &pthread->state_lock);
+
++ /* Rely on pthread_cond_wait being a cancellation point to make
++ pthread_join one too. */
+ while (pthread->state == PTHREAD_JOINABLE)
+ pthread_cond_wait (&pthread->state_cond, &pthread->state_lock);
+
+diff --git a/libpthread/pthread/pt-setcancelstate.c b/libpthread/pthread/pt-setcancelstate.c
+index 38550ee..7b60015 100644
+--- a/libpthread/pthread/pt-setcancelstate.c
++++ b/libpthread/pthread/pt-setcancelstate.c
+@@ -35,9 +35,11 @@ __pthread_setcancelstate (int state, int *oldstate)
+ break;
+ }
+
++ __pthread_mutex_lock (&p->cancel_lock);
+ if (oldstate)
+ *oldstate = p->cancel_state;
+ p->cancel_state = state;
++ __pthread_mutex_unlock (&p->cancel_lock);
+
+ return 0;
+ }
+diff --git a/libpthread/pthread/pt-setcanceltype.c b/libpthread/pthread/pt-setcanceltype.c
+index 7226a3a..3cfbe9c 100644
+--- a/libpthread/pthread/pt-setcanceltype.c
++++ b/libpthread/pthread/pt-setcanceltype.c
+@@ -35,9 +35,11 @@ __pthread_setcanceltype (int type, int *oldtype)
+ break;
+ }
+
++ __pthread_mutex_lock (&p->cancel_lock);
+ if (oldtype)
+ *oldtype = p->cancel_type;
+ p->cancel_type = type;
++ __pthread_mutex_unlock (&p->cancel_lock);
+
+ return 0;
+ }
+diff --git a/libpthread/pthread/pt-testcancel.c b/libpthread/pthread/pt-testcancel.c
+index 01f1ac9..3ba07b6 100644
+--- a/libpthread/pthread/pt-testcancel.c
++++ b/libpthread/pthread/pt-testcancel.c
+@@ -25,7 +25,12 @@ void
+ pthread_testcancel (void)
+ {
+ struct __pthread *p = _pthread_self ();
++ int cancelled;
+
+- if (p->cancel_state == PTHREAD_CANCEL_ENABLE && p->cancel_pending)
++ __pthread_mutex_lock (&p->cancel_lock);
++ cancelled = (p->cancel_state == PTHREAD_CANCEL_ENABLE) && p->cancel_pending;
++ __pthread_mutex_unlock (&p->cancel_lock);
++
++ if (cancelled)
+ pthread_exit (PTHREAD_CANCELED);
+ }
+diff --git a/libpthread/sysdeps/generic/pt-cond-brdcast.c b/libpthread/sysdeps/generic/pt-cond-brdcast.c
+index 999cc2d..ad44f83 100644
+--- a/libpthread/sysdeps/generic/pt-cond-brdcast.c
++++ b/libpthread/sysdeps/generic/pt-cond-brdcast.c
+@@ -28,16 +28,12 @@ __pthread_cond_broadcast (pthread_cond_t *cond)
+ struct __pthread *wakeup;
+
+ __pthread_spin_lock (&cond->__lock);
++ __pthread_dequeuing_iterate (cond->__queue, wakeup)
++ __pthread_wakeup (wakeup);
+
+- wakeup = cond->__queue;
+ cond->__queue = NULL;
+ __pthread_spin_unlock (&cond->__lock);
+
+- /* We can safely walk the list of waiting threads without holding
+- the lock since it is now decoupled from the condition. */
+- __pthread_dequeuing_iterate (wakeup, wakeup)
+- __pthread_wakeup (wakeup);
+-
+ return 0;
+ }
+
+diff --git a/libpthread/sysdeps/generic/pt-cond-signal.c b/libpthread/sysdeps/generic/pt-cond-signal.c
+index d7c91e6..4b5450c 100644
+--- a/libpthread/sysdeps/generic/pt-cond-signal.c
++++ b/libpthread/sysdeps/generic/pt-cond-signal.c
+@@ -21,8 +21,10 @@
+
+ #include <pt-internal.h>
+
+-static int
+-cond_signal (struct __pthread_cond *cond, int *unblocked)
++/* Unblock at least one of the threads that are blocked on condition
++ variable COND. */
++int
++__pthread_cond_signal (pthread_cond_t *cond)
+ {
+ struct __pthread *wakeup;
+
+@@ -33,24 +35,9 @@ cond_signal (struct __pthread_cond *cond, int *unblocked)
+ __pthread_spin_unlock (&cond->__lock);
+
+ if (wakeup)
+- {
+- /* We found a thread waiting for the condition to be signalled.
+- Wake it up! */
+- __pthread_wakeup (wakeup);
+- *unblocked = 1;
+- }
++ __pthread_wakeup (wakeup);
+
+ return 0;
+ }
+
+-/* Unblock at least one of the threads that are blocked on condition
+- variable COND. */
+-int
+-__pthread_cond_signal (pthread_cond_t *cond)
+-{
+- int unblocked = 0;
+-
+- return cond_signal (cond, &unblocked);
+-}
+-
+ strong_alias (__pthread_cond_signal, pthread_cond_signal);
+diff --git a/libpthread/sysdeps/generic/pt-cond-timedwait.c b/libpthread/sysdeps/generic/pt-cond-timedwait.c
+index 56eb1ec..978b0f4 100644
+--- a/libpthread/sysdeps/generic/pt-cond-timedwait.c
++++ b/libpthread/sysdeps/generic/pt-cond-timedwait.c
+@@ -35,6 +35,32 @@ __pthread_cond_timedwait (pthread_cond_t *cond,
+
+ strong_alias (__pthread_cond_timedwait, pthread_cond_timedwait);
+
++struct cancel_ctx
++ {
++ struct __pthread *wakeup;
++ pthread_cond_t *cond;
++ };
++
++static void
++cancel_hook (void *arg)
++{
++ struct cancel_ctx *ctx = arg;
++ struct __pthread *wakeup = ctx->wakeup;
++ pthread_cond_t *cond = ctx->cond;
++ int unblock;
++
++ __pthread_spin_lock (&cond->__lock);
++ /* The thread only needs to be awaken if it's blocking or about to block.
++ If it was already unblocked, it's not queued any more. */
++ unblock = wakeup->prevp != NULL;
++ if (unblock)
++ __pthread_dequeue (wakeup);
++ __pthread_spin_unlock (&cond->__lock);
++
++ if (unblock)
++ __pthread_wakeup (wakeup);
++}
++
+ /* Block on condition variable COND until ABSTIME. As a GNU
+ extension, if ABSTIME is NULL, then wait forever. MUTEX should be
+ held by the calling thread. On return, MUTEX will be held by the
+@@ -45,67 +71,108 @@ __pthread_cond_timedwait_internal (pthread_cond_t *cond,
+ const struct timespec *abstime)
+ {
+ error_t err;
+- int canceltype;
++ int cancelled, oldtype, drain;
+ clockid_t clock_id = __pthread_default_condattr.clock;
+
+- void cleanup (void *arg)
++ if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000))
++ return EINVAL;
++
++ struct __pthread *self = _pthread_self ();
++ struct cancel_ctx ctx;
++ ctx.wakeup= self;
++ ctx.cond = cond;
++
++ /* Test for a pending cancellation request, switch to deferred mode for
++ safer resource handling, and prepare the hook to call in case we're
++ cancelled while blocking. Once CANCEL_LOCK is released, the cancellation
++ hook can be called by another thread at any time. Whatever happens,
++ this function must exit with MUTEX locked.
++
++ This function contains inline implementations of pthread_testcancel and
++ pthread_setcanceltype to reduce locking overhead. */
++ __pthread_mutex_lock (&self->cancel_lock);
++ cancelled = (self->cancel_state == PTHREAD_CANCEL_ENABLE)
++ && self->cancel_pending;
++
++ if (! cancelled)
+ {
+- struct __pthread *self = _pthread_self ();
++ self->cancel_hook = cancel_hook;
++ self->cancel_hook_arg = &ctx;
++ oldtype = self->cancel_type;
++
++ if (oldtype != PTHREAD_CANCEL_DEFERRED)
++ self->cancel_type = PTHREAD_CANCEL_DEFERRED;
+
++ /* Add ourselves to the list of waiters. This is done while setting
++ the cancellation hook to simplify the cancellation procedure, i.e.
++ if the thread is queued, it can be cancelled, otherwise it is
++ already unblocked, progressing on the return path. */
+ __pthread_spin_lock (&cond->__lock);
+- if (self->prevp)
+- __pthread_dequeue (self);
++ __pthread_enqueue (&cond->__queue, self);
++ if (cond->__attr)
++ clock_id = cond->__attr->clock;
+ __pthread_spin_unlock (&cond->__lock);
+-
+- pthread_setcanceltype (canceltype, &canceltype);
+- __pthread_mutex_lock (mutex);
+ }
++ __pthread_mutex_unlock (&self->cancel_lock);
+
+- if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000))
+- return EINVAL;
+-
+- struct __pthread *self = _pthread_self ();
+-
+- /* Add ourselves to the list of waiters. */
+- __pthread_spin_lock (&cond->__lock);
+- __pthread_enqueue (&cond->__queue, self);
+- if (cond->__attr)
+- clock_id = cond->__attr->clock;
+- __pthread_spin_unlock (&cond->__lock);
++ if (cancelled)
++ pthread_exit (PTHREAD_CANCELED);
+
++ /* Release MUTEX before blocking. */
+ __pthread_mutex_unlock (mutex);
+
+- /* Enter async cancelation mode. If cancelation is disabled, then
+- this does not change anything which is exactly what we want. */
+- pthread_cleanup_push (cleanup, 0);
+- pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &canceltype);
+-
++ /* Block the thread. */
+ if (abstime)
++ err = __pthread_timedblock (self, abstime, clock_id);
++ else
+ {
+- err = __pthread_timedblock (self, abstime, clock_id);
+- if (err)
+- /* We timed out. We may need to disconnect ourself from the
+- waiter queue.
+-
+- FIXME: What do we do if we get a wakeup message before we
+- disconnect ourself? It may remain until the next time we
+- block. */
++ err = 0;
++ __pthread_block (self);
++ }
++
++ __pthread_spin_lock (&cond->__lock);
++ if (! self->prevp)
++ {
++ /* Another thread removed us from the list of waiters, which means a
++ wakeup message has been sent. It was either consumed while we were
++ blocking, or queued after we timed out and before we acquired the
++ condition lock, in which case the message queue must be drained. */
++ if (! err)
++ drain = 0;
++ else
+ {
+ assert (err == ETIMEDOUT);
+-
+- __pthread_spin_lock (&mutex->__lock);
+- if (self->prevp)
+- __pthread_dequeue (self);
+- __pthread_spin_unlock (&mutex->__lock);
++ drain = 1;
+ }
+ }
+ else
+ {
+- err = 0;
+- __pthread_block (self);
++ /* We're still in the list of waiters. Noone attempted to wake us up,
++ i.e. we timed out. */
++ assert (err == ETIMEDOUT);
++ __pthread_dequeue (self);
++ drain = 0;
+ }
++ __pthread_spin_unlock (&cond->__lock);
++
++ if (drain)
++ __pthread_block (self);
++
++ /* We're almost done. Remove the unblock hook, restore the previous
++ cancellation type, and check for a pending cancellation request. */
++ __pthread_mutex_lock (&self->cancel_lock);
++ self->cancel_hook = NULL;
++ self->cancel_hook_arg = NULL;
++ self->cancel_type = oldtype;
++ cancelled = (self->cancel_state == PTHREAD_CANCEL_ENABLE)
++ && self->cancel_pending;
++ __pthread_mutex_unlock (&self->cancel_lock);
++
++ /* Reacquire MUTEX before returning/cancelling. */
++ __pthread_mutex_lock (mutex);
+
+- pthread_cleanup_pop (1);
++ if (cancelled)
++ pthread_exit (PTHREAD_CANCELED);
+
+ return err;
+ }
+diff --git a/libpthread/sysdeps/generic/pt-mutex-timedlock.c b/libpthread/sysdeps/generic/pt-mutex-timedlock.c
+index 48bffaf..43e0eda 100644
+--- a/libpthread/sysdeps/generic/pt-mutex-timedlock.c
++++ b/libpthread/sysdeps/generic/pt-mutex-timedlock.c
+@@ -30,6 +30,8 @@ int
+ __pthread_mutex_timedlock_internal (struct __pthread_mutex *mutex,
+ const struct timespec *abstime)
+ {
++ error_t err;
++ int drain;
+ struct __pthread *self;
+ const struct __pthread_mutexattr *attr = mutex->attr;
+
+@@ -127,30 +129,37 @@ __pthread_mutex_timedlock_internal (struct __pthread_mutex *mutex,
+
+ /* Block the thread. */
+ if (abstime)
++ err = __pthread_timedblock (self, abstime, CLOCK_REALTIME);
++ else
+ {
+- error_t err;
+-
+- err = __pthread_timedblock (self, abstime, CLOCK_REALTIME);
+- if (err)
+- /* We timed out. We may need to disconnect ourself from the
+- waiter queue.
++ err = 0;
++ __pthread_block (self);
++ }
+
+- FIXME: What do we do if we get a wakeup message before we
+- disconnect ourself? It may remain until the next time we
+- block. */
+- {
+- assert (err == ETIMEDOUT);
++ __pthread_spin_lock (&mutex->__lock);
++ if (! self->prevp)
++ /* Another thread removed us from the queue, which means a wakeup message
++ has been sent. It was either consumed while we were blocking, or
++ queued after we timed out and before we acquired the mutex lock, in
++ which case the message queue must be drained. */
++ drain = err ? 1 : 0;
++ else
++ {
++ /* We're still in the queue. Noone attempted to wake us up, i.e. we
++ timed out. */
++ __pthread_dequeue (self);
++ drain = 0;
++ }
++ __pthread_spin_unlock (&mutex->__lock);
+
+- __pthread_spin_lock (&mutex->__lock);
+- if (self->prevp)
+- __pthread_dequeue (self);
+- __pthread_spin_unlock (&mutex->__lock);
++ if (drain)
++ __pthread_block (self);
+
+- return err;
+- }
++ if (err)
++ {
++ assert (err == ETIMEDOUT);
++ return err;
+ }
+- else
+- __pthread_block (self);
+
+ #if !defined(ALWAYS_TRACK_MUTEX_OWNER)
+ if (attr && attr->mutex_type != PTHREAD_MUTEX_NORMAL)
+diff --git a/libpthread/sysdeps/generic/pt-rwlock-timedrdlock.c b/libpthread/sysdeps/generic/pt-rwlock-timedrdlock.c
+index a110213..a81ca71 100644
+--- a/libpthread/sysdeps/generic/pt-rwlock-timedrdlock.c
++++ b/libpthread/sysdeps/generic/pt-rwlock-timedrdlock.c
+@@ -29,6 +29,8 @@ int
+ __pthread_rwlock_timedrdlock_internal (struct __pthread_rwlock *rwlock,
+ const struct timespec *abstime)
+ {
++ error_t err;
++ int drain;
+ struct __pthread *self;
+
+ __pthread_spin_lock (&rwlock->__lock);
+@@ -70,32 +72,37 @@ __pthread_rwlock_timedrdlock_internal (struct __pthread_rwlock *rwlock,
+
+ /* Block the thread. */
+ if (abstime)
++ err = __pthread_timedblock (self, abstime, CLOCK_REALTIME);
++ else
+ {
+- error_t err;
+-
+- err = __pthread_timedblock (self, abstime, CLOCK_REALTIME);
+- if (err)
+- /* We timed out. We may need to disconnect ourself from the
+- waiter queue.
+-
+- FIXME: What do we do if we get a wakeup message before we
+- disconnect ourself? It may remain until the next time we
+- block. */
+- {
+- assert (err == ETIMEDOUT);
+-
+- __pthread_spin_lock (&rwlock->__lock);
+- if (self->prevp)
+- /* Disconnect ourself. */
+- __pthread_dequeue (self);
+- __pthread_spin_unlock (&rwlock->__lock);
+-
+- return err;
+- }
++ err = 0;
++ __pthread_block (self);
+ }
++
++ __pthread_spin_lock (&rwlock->__lock);
++ if (! self->prevp)
++ /* Another thread removed us from the queue, which means a wakeup message
++ has been sent. It was either consumed while we were blocking, or
++ queued after we timed out and before we acquired the rwlock lock, in
++ which case the message queue must be drained. */
++ drain = err ? 1 : 0;
+ else
++ {
++ /* We're still in the queue. Noone attempted to wake us up, i.e. we
++ timed out. */
++ __pthread_dequeue (self);
++ drain = 0;
++ }
++ __pthread_spin_unlock (&rwlock->__lock);
++
++ if (drain)
+ __pthread_block (self);
+
++ if (err)
++ {
++ assert (err == ETIMEDOUT);
++ return err;
++ }
+
+ /* The reader count has already been increment by whoever woke us
+ up. */
+diff --git a/libpthread/sysdeps/generic/pt-rwlock-timedwrlock.c b/libpthread/sysdeps/generic/pt-rwlock-timedwrlock.c
+index a5cc579..e47e936 100644
+--- a/libpthread/sysdeps/generic/pt-rwlock-timedwrlock.c
++++ b/libpthread/sysdeps/generic/pt-rwlock-timedwrlock.c
+@@ -29,6 +29,8 @@ int
+ __pthread_rwlock_timedwrlock_internal (struct __pthread_rwlock *rwlock,
+ const struct timespec *abstime)
+ {
++ error_t err;
++ int drain;
+ struct __pthread *self;
+
+ __pthread_spin_lock (&rwlock->__lock);
+@@ -56,32 +58,38 @@ __pthread_rwlock_timedwrlock_internal (struct __pthread_rwlock *rwlock,
+
+ /* Block the thread. */
+ if (abstime)
++ err = __pthread_timedblock (self, abstime, CLOCK_REALTIME);
++ else
+ {
+- error_t err;
+-
+- err = __pthread_timedblock (self, abstime, CLOCK_REALTIME);
+- if (err)
+- /* We timed out. We may need to disconnect ourself from the
+- waiter queue.
+-
+- FIXME: What do we do if we get a wakeup message before we
+- disconnect ourself? It may remain until the next time we
+- block. */
+- {
+- assert (err == ETIMEDOUT);
+-
+- __pthread_spin_lock (&rwlock->__lock);
+- if (self->prevp)
+- /* Disconnect ourself. */
+- __pthread_dequeue (self);
+- __pthread_spin_unlock (&rwlock->__lock);
+-
+- return err;
+- }
++ err = 0;
++ __pthread_block (self);
+ }
++
++ __pthread_spin_lock (&rwlock->__lock);
++ if (! self->prevp)
++ /* Another thread removed us from the queue, which means a wakeup message
++ has been sent. It was either consumed while we were blocking, or
++ queued after we timed out and before we acquired the rwlock lock, in
++ which case the message queue must be drained. */
++ drain = err ? 1 : 0;
+ else
++ {
++ /* We're still in the queue. Noone attempted to wake us up, i.e. we
++ timed out. */
++ __pthread_dequeue (self);
++ drain = 0;
++ }
++ __pthread_spin_unlock (&rwlock->__lock);
++
++ if (drain)
+ __pthread_block (self);
+
++ if (err)
++ {
++ assert (err == ETIMEDOUT);
++ return err;
++ }
++
+ assert (rwlock->readers == 0);
+
+ return 0;
+diff --git a/libpthread/sysdeps/generic/pt-rwlock-unlock.c b/libpthread/sysdeps/generic/pt-rwlock-unlock.c
+index fb23a0b..212cca5 100644
+--- a/libpthread/sysdeps/generic/pt-rwlock-unlock.c
++++ b/libpthread/sysdeps/generic/pt-rwlock-unlock.c
+@@ -65,19 +65,16 @@ pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
+
+ if (rwlock->readerqueue)
+ {
+- __pthread_queue_iterate (rwlock->readerqueue, wakeup)
+- rwlock->readers ++;
++ __pthread_dequeuing_iterate (rwlock->readerqueue, wakeup)
++ {
++ rwlock->readers ++;
++ __pthread_wakeup (wakeup);
++ }
+
+- wakeup = rwlock->readerqueue;
+ rwlock->readerqueue = 0;
+
+ __pthread_spin_unlock (&rwlock->__lock);
+
+- /* We can safely walk the list of waiting threads without holding
+- the lock since it is now decoupled from the rwlock. */
+- __pthread_dequeuing_iterate (wakeup, wakeup)
+- __pthread_wakeup (wakeup);
+-
+ return 0;
+ }
+
+diff --git a/libpthread/sysdeps/generic/sem-timedwait.c b/libpthread/sysdeps/generic/sem-timedwait.c
+index 94e6dee..7ab1583 100644
+--- a/libpthread/sysdeps/generic/sem-timedwait.c
++++ b/libpthread/sysdeps/generic/sem-timedwait.c
+@@ -27,6 +27,8 @@ int
+ __sem_timedwait_internal (sem_t *restrict sem,
+ const struct timespec *restrict timeout)
+ {
++ error_t err;
++ int drain;
+ struct __pthread *self;
+
+ __pthread_spin_lock (&sem->__lock);
+@@ -52,32 +54,39 @@ __sem_timedwait_internal (sem_t *restrict sem,
+
+ /* Block the thread. */
+ if (timeout)
++ err = __pthread_timedblock (self, timeout, CLOCK_REALTIME);
++ else
+ {
+- error_t err;
+-
+- err = __pthread_timedblock (self, timeout, CLOCK_REALTIME);
+- if (err)
+- /* We timed out. We may need to disconnect ourself from the
+- waiter queue.
+-
+- FIXME: What do we do if we get a wakeup message before we
+- disconnect ourself? It may remain until the next time we
+- block. */
+- {
+- assert (err == ETIMEDOUT);
+-
+- __pthread_spin_lock (&sem->__lock);
+- if (self->prevp)
+- __pthread_dequeue (self);
+- __pthread_spin_unlock (&sem->__lock);
+-
+- errno = err;
+- return -1;
+- }
++ err = 0;
++ __pthread_block (self);
+ }
++
++ __pthread_spin_lock (&sem->__lock);
++ if (! self->prevp)
++ /* Another thread removed us from the queue, which means a wakeup message
++ has been sent. It was either consumed while we were blocking, or
++ queued after we timed out and before we acquired the semaphore lock, in
++ which case the message queue must be drained. */
++ drain = err ? 1 : 0;
+ else
++ {
++ /* We're still in the queue. Noone attempted to wake us up, i.e. we
++ timed out. */
++ __pthread_dequeue (self);
++ drain = 0;
++ }
++ __pthread_spin_unlock (&sem->__lock);
++
++ if (drain)
+ __pthread_block (self);
+
++ if (err)
++ {
++ assert (err == ETIMEDOUT);
++ errno = err;
++ return -1;
++ }
++
+ return 0;
+ }
+
+diff --git a/libpthread/sysdeps/mach/hurd/pt-docancel.c b/libpthread/sysdeps/mach/hurd/pt-docancel.c
+index 105c6fd..b3a5507 100644
+--- a/libpthread/sysdeps/mach/hurd/pt-docancel.c
++++ b/libpthread/sysdeps/mach/hurd/pt-docancel.c
+@@ -36,6 +36,8 @@ __pthread_do_cancel (struct __pthread *p)
+ assert (p->cancel_pending == 1);
+ assert (p->cancel_state == PTHREAD_CANCEL_ENABLE);
+
++ __pthread_mutex_unlock (&p->cancel_lock);
++
+ ktid = __mach_thread_self ();
+ me = p->kernel_thread == ktid;
+ __mach_port_deallocate (__mach_task_self (), ktid);
+diff --git a/libpthread/sysdeps/mach/pt-thread-alloc.c b/libpthread/sysdeps/mach/pt-thread-alloc.c
+index 3d7c046..794f63e 100644
+--- a/libpthread/sysdeps/mach/pt-thread-alloc.c
++++ b/libpthread/sysdeps/mach/pt-thread-alloc.c
+@@ -55,6 +55,10 @@ create_wakeupmsg (struct __pthread *thread)
+ return EAGAIN;
+ }
+
++ /* No need to queue more than one wakeup message on this port. */
++ mach_port_set_qlimit (__mach_task_self (),
++ thread->wakeupmsg.msgh_remote_port, 1);
++
+ return 0;
+ }
+
+diff --git a/libpthread/sysdeps/mach/pt-wakeup.c b/libpthread/sysdeps/mach/pt-wakeup.c
+index 4920d10..95fdbf9 100644
+--- a/libpthread/sysdeps/mach/pt-wakeup.c
++++ b/libpthread/sysdeps/mach/pt-wakeup.c
+@@ -31,8 +31,8 @@ __pthread_wakeup (struct __pthread *thread)
+ {
+ error_t err;
+
+- err = __mach_msg (&thread->wakeupmsg, MACH_SEND_MSG,
++ err = __mach_msg (&thread->wakeupmsg, MACH_SEND_MSG | MACH_SEND_TIMEOUT,
+ sizeof (thread->wakeupmsg), 0, MACH_PORT_NULL,
+- MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
++ 0 , MACH_PORT_NULL);
+ assert_perror (err);
+ }
Added: glibc-package/trunk/debian/patches/hurd-i386/libpthread_hurd_cond_timedwait.diff
===================================================================
--- glibc-package/trunk/debian/patches/hurd-i386/libpthread_hurd_cond_timedwait.diff (rev 0)
+++ glibc-package/trunk/debian/patches/hurd-i386/libpthread_hurd_cond_timedwait.diff 2013-02-24 18:16:00 UTC (rev 5497)
@@ -0,0 +1,331 @@
+commit 87e9dfeae82e35cff3d7690e3e8e631d408cf665
+Author: Richard Braun <rbraun@sceen.net>
+Date: Sun Feb 10 19:59:24 2013 +0100
+
+ Add pthread_hurd_cond_timedwait_np
+
+ This new Hurd-specific function is meant to allow Hurd servers to wait
+ for events during a bounded period of time.
+
+ * Makefile (libpthread-routines): Add pt-hurd-cond-timedwait.
+ * Versions: Include pthread_hurd_cond_timedwait_np in version GLIBC_2.17
+ of libpthread.
+ * sysdeps/mach/hurd/bits/pthread-np.h (pthread_hurd_cond_timedwait_np): New
+ declaration.
+ * sysdeps/mach/hurd/pt-hurd-cond-timedwait.c: New file that provides
+ __pthread_hurd_cond_timedwait_internal and __pthread_hurd_cond_timedwait_np.
+ * sysdeps/mach/hurd/pt-hurd-cond-wait.c (__pthread_hurd_cond_wait_np):
+ Rewrite as a call to __pthread_hurd_cond_timedwait_internal with no timeout.
+
+diff --git a/libpthread/Makefile b/libpthread/Makefile
+index 2c7645d..c57f1a0 100644
+--- a/libpthread/Makefile
++++ b/libpthread/Makefile
+@@ -115,6 +115,7 @@ libpthread-routines := pt-attr pt-attr-destroy pt-attr-getdetachstate \
+ pt-cond-wait \
+ pt-cond-timedwait \
+ pt-hurd-cond-wait \
++ pt-hurd-cond-timedwait \
+ \
+ pt-stack-alloc \
+ pt-thread-alloc \
+--- a/Versions.def
++++ b/Versions.def
+@@ -98,6 +98,7 @@ libpthread {
+ GLIBC_2.11
+ GLIBC_2.12
+ GLIBC_2.13_DEBIAN_38
++ GLIBC_2.13_DEBIAN_39
+ GLIBC_PRIVATE
+ }
+ libresolv {
+diff --git a/libpthread/Versions b/libpthread/Versions
+index 8573637..3d151cf 100644
+--- a/libpthread/Versions
++++ b/libpthread/Versions
+@@ -132,4 +132,7 @@ libpthread {
+ GLIBC_2.13_DEBIAN_38 {
+ pthread_hurd_cond_wait_np;
+ }
++ GLIBC_2.13_DEBIAN_39 {
++ pthread_hurd_cond_timedwait_np;
++ }
+ }
+diff --git a/libpthread/sysdeps/mach/hurd/bits/pthread-np.h b/libpthread/sysdeps/mach/hurd/bits/pthread-np.h
+index 9817a06..5f75e06 100644
+--- a/libpthread/sysdeps/mach/hurd/bits/pthread-np.h
++++ b/libpthread/sysdeps/mach/hurd/bits/pthread-np.h
+@@ -29,4 +29,10 @@
+ extern int pthread_hurd_cond_wait_np (pthread_cond_t *__restrict __cond,
+ pthread_mutex_t *__restrict __mutex);
+
++/* Same as pthread_cond_timedwait, but for Hurd-specific cancellation.
++ See hurd_thread_cancel. */
++extern int pthread_hurd_cond_timedwait_np (pthread_cond_t *__restrict __cond,
++ pthread_mutex_t *__restrict __mutex,
++ const struct timespec *abstime);
++
+ #endif /* bits/pthread-np.h */
+diff --git a/libpthread/sysdeps/mach/hurd/pt-hurd-cond-timedwait.c b/libpthread/sysdeps/mach/hurd/pt-hurd-cond-timedwait.c
+new file mode 100644
+index 0000000..7491e0e
+--- /dev/null
++++ b/libpthread/sysdeps/mach/hurd/pt-hurd-cond-timedwait.c
+@@ -0,0 +1,169 @@
++/* pthread_hurd_cond_timedwait_np. Hurd-specific wait on a condition.
++ Copyright (C) 2012 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 <pthread.h>
++#include <assert.h>
++#include <hurd/signal.h>
++
++#include <pt-internal.h>
++
++extern int __pthread_hurd_cond_timedwait_internal (pthread_cond_t *cond,
++ pthread_mutex_t *mutex,
++ const struct timespec *abstime);
++
++int
++__pthread_hurd_cond_timedwait_np (pthread_cond_t *cond,
++ pthread_mutex_t *mutex,
++ const struct timespec *abstime)
++{
++ return __pthread_hurd_cond_timedwait_internal (cond, mutex, abstime);
++}
++
++strong_alias (__pthread_hurd_cond_timedwait_np, pthread_hurd_cond_timedwait_np);
++
++int
++__pthread_hurd_cond_timedwait_internal (pthread_cond_t *cond,
++ pthread_mutex_t *mutex,
++ const struct timespec *abstime)
++{
++ struct hurd_sigstate *ss = _hurd_self_sigstate ();
++ struct __pthread *self = _pthread_self ();
++ error_t err;
++ int cancel, drain;
++ clockid_t clock_id = __pthread_default_condattr.clock;
++
++ /* This function will be called by hurd_thread_cancel while we are blocked
++ We wake up our thread if it's still blocking or about to block, so it will
++ progress and notice the cancellation flag. */
++ void cancel_me (void)
++ {
++ int unblock;
++
++ __pthread_spin_lock (&cond->__lock);
++ /* The thread only needs to be awaken if it's blocking or about to block.
++ If it was already unblocked, it's not queued any more. */
++ unblock = self->prevp != NULL;
++ if (unblock)
++ __pthread_dequeue (self);
++ __pthread_spin_unlock (&cond->__lock);
++
++ if (unblock)
++ __pthread_wakeup (self);
++ }
++
++ assert (ss->intr_port == MACH_PORT_NULL); /* Sanity check for signal bugs. */
++
++ if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000))
++ return EINVAL;
++
++ /* Atomically enqueue our thread on the condition variable's queue of
++ waiters, and mark our sigstate to indicate that `cancel_me' must be
++ called to wake us up. We must hold the sigstate lock while acquiring
++ the condition variable's lock and tweaking it, so that
++ hurd_thread_cancel can never suspend us and then deadlock waiting for
++ the condition variable's lock. */
++
++ __spin_lock (&ss->lock);
++ __pthread_spin_lock (&cond->__lock);
++ cancel = ss->cancel;
++ if (cancel)
++ /* We were cancelled before doing anything. Don't block at all. */
++ ss->cancel = 0;
++ else
++ {
++ /* Put us on the queue so that pthread_cond_broadcast will know to wake
++ us up. */
++ __pthread_enqueue (&cond->__queue, self);
++ if (cond->__attr)
++ clock_id = cond->__attr->clock;
++ /* Tell hurd_thread_cancel how to unblock us. */
++ ss->cancel_hook = &cancel_me;
++ }
++ __pthread_spin_unlock (&cond->__lock);
++ __spin_unlock (&ss->lock);
++
++ if (cancel)
++ {
++ /* Cancelled on entry. Just leave the mutex locked. */
++ mutex = NULL;
++
++ __spin_lock (&ss->lock);
++ }
++ else
++ {
++ /* Release MUTEX before blocking. */
++ __pthread_mutex_unlock (mutex);
++
++ /* Block the thread. */
++ if (abstime)
++ err = __pthread_timedblock (self, abstime, clock_id);
++ else
++ {
++ err = 0;
++ __pthread_block (self);
++ }
++
++ /* As it was done when enqueueing, prevent hurd_thread_cancel from
++ suspending us while the condition lock is held. */
++ __spin_lock (&ss->lock);
++ __pthread_spin_lock (&cond->__lock);
++ if (! self->prevp)
++ /* Another thread removed us from the list of waiters, which means
++ a wakeup message has been sent. It was either consumed while
++ we were blocking, or queued after we timed out and before we
++ acquired the condition lock, in which case the message queue
++ must be drained. */
++ drain = err ? 1 : 0;
++ else
++ {
++ /* We're still in the list of waiters. Noone attempted to wake us
++ up, i.e. we timed out. */
++ __pthread_dequeue (self);
++ drain = 0;
++ }
++ __pthread_spin_unlock (&cond->__lock);
++
++ if (drain)
++ __pthread_block (self);
++ }
++
++ /* Clear the hook, now that we are done blocking. */
++ ss->cancel_hook = NULL;
++ /* Check the cancellation flag; we might have unblocked due to
++ cancellation rather than a normal pthread_cond_signal or
++ pthread_cond_broadcast (or we might have just happened to get cancelled
++ right after waking up). */
++ cancel |= ss->cancel;
++ ss->cancel = 0;
++ __spin_unlock (&ss->lock);
++
++ if (mutex)
++ /* Reacquire the mutex and return. */
++ __pthread_mutex_lock (mutex);
++
++ if (cancel)
++ return EINTR;
++ else if (err)
++ {
++ assert (err == ETIMEDOUT);
++ return err;
++ }
++
++ return 0;
++}
+diff --git a/libpthread/sysdeps/mach/hurd/pt-hurd-cond-wait.c b/libpthread/sysdeps/mach/hurd/pt-hurd-cond-wait.c
+index d2b5847..5e7c007 100644
+--- a/libpthread/sysdeps/mach/hurd/pt-hurd-cond-wait.c
++++ b/libpthread/sysdeps/mach/hurd/pt-hurd-cond-wait.c
+@@ -23,71 +23,19 @@
+
+ #include <pt-internal.h>
+
++/* Implemented in pt-hurd-cond-timedwait.c. */
++extern int __pthread_hurd_cond_timedwait_internal (pthread_cond_t *cond,
++ pthread_mutex_t *mutex,
++ const struct timespec *abstime);
++
+ int
+-pthread_hurd_cond_wait_np (pthread_cond_t *cond, pthread_mutex_t *mutex)
++__pthread_hurd_cond_wait_np (pthread_cond_t *cond,
++ pthread_mutex_t *mutex)
+ {
+- /* This function will be called by hurd_thread_cancel while we are blocked
+- We wake up all threads blocked on COND, so our thread will wake up and
+- notice the cancellation flag. */
+- void cancel_me (void)
+- {
+- pthread_cond_broadcast (cond);
+- }
+- struct hurd_sigstate *ss = _hurd_self_sigstate ();
+- struct __pthread *self = _pthread_self ();
+- int cancel;
+-
+- assert (ss->intr_port == MACH_PORT_NULL); /* Sanity check for signal bugs. */
+-
+- /* Atomically enqueue our thread on the condition variable's queue of
+- waiters, and mark our sigstate to indicate that `cancel_me' must be
+- called to wake us up. We must hold the sigstate lock while acquiring
+- the condition variable's lock and tweaking it, so that
+- hurd_thread_cancel can never suspend us and then deadlock in
+- pthread_cond_broadcast waiting for the condition variable's lock. */
+-
+- __spin_lock (&ss->lock);
+- __pthread_spin_lock (&cond->__lock);
+- cancel = ss->cancel;
+- if (cancel)
+- /* We were cancelled before doing anything. Don't block at all. */
+- ss->cancel = 0;
+- else
+- {
+- /* Put us on the queue so that pthread_cond_broadcast will know to wake
+- us up. */
+- __pthread_enqueue (&cond->__queue, self);
+- /* Tell hurd_thread_cancel how to unblock us. */
+- ss->cancel_hook = &cancel_me;
+- }
+- __pthread_spin_unlock (&cond->__lock);
+- __spin_unlock (&ss->lock);
+-
++ error_t err;
+
+- if (cancel)
+- /* Cancelled on entry. Just leave the mutex locked. */
+- mutex = NULL;
+- else
+- {
+- /* Now unlock the mutex and block until woken. */
+- __pthread_mutex_unlock (mutex);
+- __pthread_block (self);
+- }
+-
+- __spin_lock (&ss->lock);
+- /* Clear the hook, now that we are done blocking. */
+- ss->cancel_hook = NULL;
+- /* Check the cancellation flag; we might have unblocked due to
+- cancellation rather than a normal pthread_cond_signal or
+- pthread_cond_broadcast (or we might have just happened to get cancelled
+- right after waking up). */
+- cancel |= ss->cancel;
+- ss->cancel = 0;
+- __spin_unlock (&ss->lock);
+-
+- if (mutex)
+- /* Reacquire the mutex and return. */
+- __pthread_mutex_lock (mutex);
+-
+- return cancel;
++ err = __pthread_hurd_cond_timedwait_internal (cond, mutex, NULL);
++ return (err == EINTR);
+ }
++
++strong_alias (__pthread_hurd_cond_wait_np, pthread_hurd_cond_wait_np);
Modified: glibc-package/trunk/debian/patches/series
===================================================================
--- glibc-package/trunk/debian/patches/series 2013-02-24 16:44:46 UTC (rev 5496)
+++ glibc-package/trunk/debian/patches/series 2013-02-24 18:16:00 UTC (rev 5497)
@@ -217,6 +217,8 @@
hurd-i386/unsubmitted-select-EINTR.diff
hurd-i386/cvs-libpthread_lock.diff
hurd-i386/tg-pie-sbrk.diff
+hurd-i386/libpthread_cancellation.diff
+hurd-i386/libpthread_hurd_cond_timedwait.diff
kfreebsd/submitted-libc_once.diff
kfreebsd/local-getaddrinfo-freebsd-kernel.diff
Reply to: