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 <rbr...@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 <rbr...@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 -- To UNSUBSCRIBE, email to debian-glibc-requ...@lists.debian.org with a subject of "unsubscribe". Trouble? Contact listmas...@lists.debian.org Archive: http://lists.debian.org/e1u9g7f-0003eg...@vasks.debian.org