summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pthread/pt-internal.h19
-rw-r--r--sysdeps/l4/hurd/pt-wakeup.c18
2 files changed, 29 insertions, 8 deletions
diff --git a/pthread/pt-internal.h b/pthread/pt-internal.h
index 41fbc830..853d739d 100644
--- a/pthread/pt-internal.h
+++ b/pthread/pt-internal.h
@@ -122,15 +122,22 @@ __pthread_dequeue (struct __pthread *thread)
}
/* Iterate over QUEUE storing each element in ELEMENT. */
-#define __pthread_queue_iterate(queue, element) \
- for (element = queue; element; element = element->next)
+#define __pthread_queue_iterate(queue, element) \
+ for (struct __pthread *__pdi_next = (queue); \
+ ((element) = __pdi_next) \
+ && ((__pdi_next = __pdi_next->next), \
+ true); \
+ )
/* Iterate over QUEUE dequeuing each element, storing it in
ELEMENT. */
-#define __pthread_dequeuing_iterate(queue, element) \
- for (element = queue; \
- element && ((element->prevp = 0), 1); \
- element = element->next)
+#define __pthread_dequeuing_iterate(queue, element) \
+ for (struct __pthread *__pdi_next = (queue); \
+ ((element) = __pdi_next) \
+ && ((__pdi_next = __pdi_next->next), \
+ ((element)->prevp = 0), \
+ true); \
+ )
/* The total number of threads currently active. */
extern atomic_fast32_t __pthread_total;
diff --git a/sysdeps/l4/hurd/pt-wakeup.c b/sysdeps/l4/hurd/pt-wakeup.c
index 2225cca0..e568a6f9 100644
--- a/sysdeps/l4/hurd/pt-wakeup.c
+++ b/sysdeps/l4/hurd/pt-wakeup.c
@@ -27,6 +27,20 @@
void
__pthread_wakeup (struct __pthread *thread)
{
- long ret = futex_wake (&thread->threadid, INT_MAX);
- assert (ret == 1);
+ /* We need to loop here as the blocked thread may not yet be
+ blocked! Here's what happens when a thread blocks: it registers
+ itself as blocked, drops the relevant lock and then actually
+ blocks (via __pthread_block). This means that after dropping the
+ lock and before blocking, it may be interrupted and another
+ thread may try to wake it. */
+ long ret;
+ do
+ {
+ ret = futex_wake (&thread->threadid, INT_MAX);
+ assertx (ret <= 1, "tid: %x, ret: %d", thread->threadid, ret);
+
+ if (ret == 0)
+ l4_thread_switch (thread->threadid);
+ }
+ while (ret == 0);
}