summaryrefslogtreecommitdiffstats
path: root/lib/libthr
diff options
context:
space:
mode:
authordavidxu <davidxu@FreeBSD.org>2012-03-16 04:35:52 +0000
committerdavidxu <davidxu@FreeBSD.org>2012-03-16 04:35:52 +0000
commit02e067d118d4246773de1b129e5154ab8d455aff (patch)
treee238c1fe839072498e9acbcafb15e2e66020ae0e /lib/libthr
parentdd9eff8d3914d10be3494051291f65b525a21fda (diff)
downloadFreeBSD-src-02e067d118d4246773de1b129e5154ab8d455aff.zip
FreeBSD-src-02e067d118d4246773de1b129e5154ab8d455aff.tar.gz
When destroying a barrier, waiting all threads exit the barrier,
this makes it possible a thread received PTHREAD_BARRIER_SERIAL_THREAD immediately free memory area of the barrier.
Diffstat (limited to 'lib/libthr')
-rw-r--r--lib/libthr/thread/thr_barrier.c27
-rw-r--r--lib/libthr/thread/thr_private.h8
2 files changed, 31 insertions, 4 deletions
diff --git a/lib/libthr/thread/thr_barrier.c b/lib/libthr/thread/thr_barrier.c
index bbd4447..86f880e 100644
--- a/lib/libthr/thread/thr_barrier.c
+++ b/lib/libthr/thread/thr_barrier.c
@@ -42,13 +42,34 @@ int
_pthread_barrier_destroy(pthread_barrier_t *barrier)
{
pthread_barrier_t bar;
+ struct pthread *curthread;
if (barrier == NULL || *barrier == NULL)
return (EINVAL);
+ curthread = _get_curthread();
bar = *barrier;
- if (bar->b_waiters > 0)
+ THR_UMUTEX_LOCK(curthread, &bar->b_lock);
+ if (bar->b_destroying) {
+ THR_UMUTEX_UNLOCK(curthread, &bar->b_lock);
return (EBUSY);
+ }
+ bar->b_destroying = 1;
+ do {
+ if (bar->b_waiters > 0) {
+ bar->b_destroying = 0;
+ THR_UMUTEX_UNLOCK(curthread, &bar->b_lock);
+ return (EBUSY);
+ }
+ if (bar->b_refcount != 0) {
+ _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0);
+ THR_UMUTEX_LOCK(curthread, &bar->b_lock);
+ } else
+ break;
+ } while (1);
+ bar->b_destroying = 0;
+ THR_UMUTEX_UNLOCK(curthread, &bar->b_lock);
+
*barrier = NULL;
free(bar);
return (0);
@@ -74,6 +95,7 @@ _pthread_barrier_init(pthread_barrier_t *barrier,
bar->b_cycle = 0;
bar->b_waiters = 0;
bar->b_count = count;
+ bar->b_refcount = 0;
*barrier = bar;
return (0);
@@ -101,11 +123,14 @@ _pthread_barrier_wait(pthread_barrier_t *barrier)
ret = PTHREAD_BARRIER_SERIAL_THREAD;
} else {
cycle = bar->b_cycle;
+ bar->b_refcount++;
do {
_thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0);
THR_UMUTEX_LOCK(curthread, &bar->b_lock);
/* test cycle to avoid bogus wakeup */
} while (cycle == bar->b_cycle);
+ if (--bar->b_refcount == 0 && bar->b_destroying)
+ _thr_ucond_broadcast(&bar->b_cv);
THR_UMUTEX_UNLOCK(curthread, &bar->b_lock);
ret = 0;
}
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index 7a9727f..4b9219d 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -182,9 +182,11 @@ struct pthread_cond_attr {
struct pthread_barrier {
struct umutex b_lock;
struct ucond b_cv;
- volatile int64_t b_cycle;
- volatile int b_count;
- volatile int b_waiters;
+ int64_t b_cycle;
+ int b_count;
+ int b_waiters;
+ int b_refcount;
+ int b_destroying;
};
struct pthread_barrierattr {
OpenPOWER on IntegriCloud