git-cond_destroy
authorGNU Libc Maintainers <debian-glibc@lists.debian.org>
Mon, 13 Jul 2020 19:34:17 +0000 (20:34 +0100)
committerAurelien Jarno <aurel32@debian.org>
Mon, 13 Jul 2020 19:34:17 +0000 (20:34 +0100)
commit faae4b2bdd692d929037c80c3315f716f02f3b00
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
Date:   Sun Feb 9 19:19:25 2020 +0000

    htl: make pthread_cond_destroy return EBUSY on waiters

Gbp-Pq: Topic hurd-i386
Gbp-Pq: Name git-cond_destroy.diff

sysdeps/htl/bits/types/struct___pthread_cond.h
sysdeps/htl/pt-cond-destroy.c
sysdeps/htl/pt-cond-timedwait.c
sysdeps/mach/hurd/htl/pt-hurd-cond-timedwait.c

index 150a37c4c9e6ba8eca3e4c3f479620e485dabeb0..c040b171acc74ab0bcd8f7f52f11c05342725419 100644 (file)
@@ -27,12 +27,12 @@ struct __pthread_cond
   __pthread_spinlock_t __lock;
   struct __pthread *__queue;
   struct __pthread_condattr *__attr;
-  struct __pthread_condimpl *__impl;
+  unsigned int __wrefs;
   void *__data;
 };
 
 /* Initializer for a condition variable.  */
 #define __PTHREAD_COND_INITIALIZER \
-  { __PTHREAD_SPIN_LOCK_INITIALIZER, NULL, NULL, NULL, NULL }
+  { __PTHREAD_SPIN_LOCK_INITIALIZER, NULL, NULL, 0, NULL }
 
 #endif /* bits/types/struct___pthread_cond.h */
index 62cc77b0d2088abd9b3cec79dbea41b0411b3c0c..e969f72377c5cb44ee812bcfe01737f5b50222c8 100644 (file)
 int
 __pthread_cond_destroy (pthread_cond_t *cond)
 {
+  /* Set the wake request flag. */
+  unsigned int wrefs = atomic_fetch_or_acquire (&cond->__wrefs, 1);
+
+  __pthread_spin_lock (&cond->__lock);
+  if (cond->__queue)
+    {
+      __pthread_spin_unlock (&cond->__lock);
+      return EBUSY;
+    }
+  __pthread_spin_unlock (&cond->__lock);
+
+  while (wrefs >> 1 != 0)
+    {
+      __gsync_wait (__mach_task_self (), (vm_offset_t) &cond->__wrefs, wrefs,
+                 0, 0, 0);
+      wrefs = atomic_load_acquire (&cond->__wrefs);
+    }
+  /* The memory the condvar occupies can now be reused.  */
+
   return 0;
 }
 
index d9ce23b68296174c7185ce9203082656e354feb0..c7cbc0a2dcb49504fb2fa8f73843ae74b9218cbe 100644 (file)
@@ -122,6 +122,10 @@ __pthread_cond_timedwait_internal (pthread_cond_t *cond,
   /* Release MUTEX before blocking.  */
   __pthread_mutex_unlock (mutex);
 
+  /* Increase the waiter reference count.  Relaxed MO is sufficient because
+     we only need to synchronize when decrementing the reference count.  */
+  atomic_fetch_add_relaxed (&cond->__wrefs, 2);
+
   /* Block the thread.  */
   if (abstime != NULL)
     err = __pthread_timedblock (self, abstime, clock_id);
@@ -156,6 +160,13 @@ __pthread_cond_timedwait_internal (pthread_cond_t *cond,
     }
   __pthread_spin_unlock (&cond->__lock);
 
+  /* If destruction is pending (i.e., the wake-request flag is nonzero) and we
+     are the last waiter (prior value of __wrefs was 1 << 1), then wake any
+     threads waiting in pthread_cond_destroy.  Release MO to synchronize with
+     these threads.  Don't bother clearing the wake-up request flag.  */
+  if ((atomic_fetch_add_release (&cond->__wrefs, -2)) == 3)
+    __gsync_wake (__mach_task_self (), (vm_offset_t) &cond->__wrefs, 0, 0);
+
   if (drain)
     __pthread_block (self);
 
index 12dd8634d47c9051ec42dea0e093269ea795ef1f..4f3bd0229d7b31af43084a04f47c00d7cecb9302 100644 (file)
@@ -111,6 +111,10 @@ __pthread_hurd_cond_timedwait_internal (pthread_cond_t *cond,
       /* Release MUTEX before blocking.  */
       __pthread_mutex_unlock (mutex);
 
+  /* Increase the waiter reference count.  Relaxed MO is sufficient because
+     we only need to synchronize when decrementing the reference count.  */
+  atomic_fetch_add_relaxed (&cond->__wrefs, 2);
+
       /* Block the thread.  */
       if (abstime != NULL)
        err = __pthread_timedblock (self, abstime, clock_id);
@@ -144,6 +148,13 @@ __pthread_hurd_cond_timedwait_internal (pthread_cond_t *cond,
        __pthread_block (self);
     }
 
+  /* If destruction is pending (i.e., the wake-request flag is nonzero) and we
+     are the last waiter (prior value of __wrefs was 1 << 1), then wake any
+     threads waiting in pthread_cond_destroy.  Release MO to synchronize with
+     these threads.  Don't bother clearing the wake-up request flag.  */
+  if ((atomic_fetch_add_release (&cond->__wrefs, -2)) == 3)
+    __gsync_wake (__mach_task_self (), (vm_offset_t) &cond->__wrefs, 0, 0);
+
   /* Clear the hook, now that we are done blocking.  */
   ss->cancel_hook = NULL;
   /* Check the cancellation flag; we might have unblocked due to