From f030a5765baf9d81bf53bee87ec40b649410c853 Mon Sep 17 00:00:00 2001 From: GNU Libc Maintainers Date: Thu, 15 Aug 2024 11:21:36 +0200 Subject: [PATCH] git-cond_destroy Committed for glibc 2.32 commit faae4b2bdd692d929037c80c3315f716f02f3b00 Author: Samuel Thibault 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 --- .../htl/bits/types/struct___pthread_cond.h | 4 ++-- sysdeps/htl/pt-cond-destroy.c | 19 +++++++++++++++++++ sysdeps/htl/pt-cond-timedwait.c | 11 +++++++++++ .../mach/hurd/htl/pt-hurd-cond-timedwait.c | 11 +++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/sysdeps/htl/bits/types/struct___pthread_cond.h b/sysdeps/htl/bits/types/struct___pthread_cond.h index 150a37c4c..c040b171a 100644 --- a/sysdeps/htl/bits/types/struct___pthread_cond.h +++ b/sysdeps/htl/bits/types/struct___pthread_cond.h @@ -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 */ diff --git a/sysdeps/htl/pt-cond-destroy.c b/sysdeps/htl/pt-cond-destroy.c index 62cc77b0d..e969f7237 100644 --- a/sysdeps/htl/pt-cond-destroy.c +++ b/sysdeps/htl/pt-cond-destroy.c @@ -22,6 +22,25 @@ 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; } diff --git a/sysdeps/htl/pt-cond-timedwait.c b/sysdeps/htl/pt-cond-timedwait.c index d9ce23b68..c7cbc0a2d 100644 --- a/sysdeps/htl/pt-cond-timedwait.c +++ b/sysdeps/htl/pt-cond-timedwait.c @@ -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); diff --git a/sysdeps/mach/hurd/htl/pt-hurd-cond-timedwait.c b/sysdeps/mach/hurd/htl/pt-hurd-cond-timedwait.c index 12dd8634d..4f3bd0229 100644 --- a/sysdeps/mach/hurd/htl/pt-hurd-cond-timedwait.c +++ b/sysdeps/mach/hurd/htl/pt-hurd-cond-timedwait.c @@ -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 -- 2.30.2