summaryrefslogtreecommitdiffstats
path: root/lib/libthr/thread/thr_barrier.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libthr/thread/thr_barrier.c')
-rw-r--r--lib/libthr/thread/thr_barrier.c122
1 files changed, 50 insertions, 72 deletions
diff --git a/lib/libthr/thread/thr_barrier.c b/lib/libthr/thread/thr_barrier.c
index 547a721..afb6a40 100644
--- a/lib/libthr/thread/thr_barrier.c
+++ b/lib/libthr/thread/thr_barrier.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2004 Michael Telahun Makonnen <mtm@FreeBSD.Org>
+ * Copyright (c) 2003 David Xu <davidxu@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -26,104 +26,82 @@
* $FreeBSD$
*/
-#include <pthread.h>
+#include <errno.h>
#include <stdlib.h>
-#include <string.h>
+#include <pthread.h>
#include "thr_private.h"
-__weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy);
-__weak_reference(_pthread_barrier_init, pthread_barrier_init);
-__weak_reference(_pthread_barrier_wait, pthread_barrier_wait);
+__weak_reference(_pthread_barrier_init, pthread_barrier_init);
+__weak_reference(_pthread_barrier_wait, pthread_barrier_wait);
+__weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy);
int
_pthread_barrier_destroy(pthread_barrier_t *barrier)
{
- if (*barrier == NULL)
+ pthread_barrier_t bar;
+
+ if (barrier == NULL || *barrier == NULL)
return (EINVAL);
- if ((*barrier)->b_subtotal > 0)
+
+ bar = *barrier;
+ if (bar->b_waiters > 0)
return (EBUSY);
- PTHREAD_ASSERT((*barrier)->b_subtotal == 0,
- "barrier count must be zero when destroyed");
- free(*barrier);
*barrier = NULL;
+ free(bar);
return (0);
}
int
_pthread_barrier_init(pthread_barrier_t *barrier,
- const pthread_barrierattr_t attr, unsigned int count)
+ const pthread_barrierattr_t *attr, int count)
{
- if (count < 1)
+ pthread_barrier_t bar;
+
+ if (barrier == NULL || count <= 0)
return (EINVAL);
- *barrier =
- (struct pthread_barrier *)malloc(sizeof(struct pthread_barrier));
- if (*barrier == NULL)
+
+ bar = malloc(sizeof(struct pthread_barrier));
+ if (bar == NULL)
return (ENOMEM);
- memset((void *)*barrier, 0, sizeof(struct pthread_barrier));
- (*barrier)->b_total = count;
- TAILQ_INIT(&(*barrier)->b_barrq);
+
+ _thr_umtx_init(&bar->b_lock);
+ bar->b_cycle = 0;
+ bar->b_waiters = 0;
+ bar->b_count = count;
+ *barrier = bar;
+
return (0);
}
int
_pthread_barrier_wait(pthread_barrier_t *barrier)
{
- struct pthread_barrier *b;
- struct pthread *ptd;
- int error;
+ struct pthread *curthread = _get_curthread();
+ pthread_barrier_t bar;
+ long cycle;
+ int ret;
- if (*barrier == NULL)
+ if (barrier == NULL || *barrier == NULL)
return (EINVAL);
- /*
- * Check if threads waiting on the barrier can be released. If
- * so, release them and make this last thread the special thread.
- */
- error = 0;
- b = *barrier;
- UMTX_LOCK(&b->b_lock);
- if (b->b_subtotal == (b->b_total - 1)) {
- TAILQ_FOREACH(ptd, &b->b_barrq, sqe) {
- PTHREAD_LOCK(ptd);
- TAILQ_REMOVE(&b->b_barrq, ptd, sqe);
- ptd->flags &= ~PTHREAD_FLAGS_IN_BARRQ;
- ptd->flags |= PTHREAD_FLAGS_BARR_REL;
- PTHREAD_WAKE(ptd);
- PTHREAD_UNLOCK(ptd);
- }
- b->b_subtotal = 0;
- UMTX_UNLOCK(&b->b_lock);
- return (PTHREAD_BARRIER_SERIAL_THREAD);
+ bar = *barrier;
+ THR_UMTX_LOCK(curthread, &bar->b_lock);
+ if (++bar->b_waiters == bar->b_count) {
+ /* Current thread is lastest thread */
+ bar->b_waiters = 0;
+ bar->b_cycle++;
+ _thr_umtx_wake(&bar->b_cycle, bar->b_count);
+ THR_UMTX_UNLOCK(curthread, &bar->b_lock);
+ ret = PTHREAD_BARRIER_SERIAL_THREAD;
+ } else {
+ cycle = bar->b_cycle;
+ THR_UMTX_UNLOCK(curthread, &bar->b_lock);
+ do {
+ _thr_umtx_wait(&bar->b_cycle, cycle, NULL);
+ /* test cycle to avoid bogus wakeup */
+ } while (cycle == bar->b_cycle);
+ ret = 0;
}
-
- /*
- * More threads need to reach the barrier. Suspend this thread.
- */
- PTHREAD_LOCK(curthread);
- TAILQ_INSERT_HEAD(&b->b_barrq, curthread, sqe);
- curthread->flags |= PTHREAD_FLAGS_IN_BARRQ;
- PTHREAD_UNLOCK(curthread);
- b->b_subtotal++;
- PTHREAD_ASSERT(b->b_subtotal < b->b_total,
- "the number of threads waiting at a barrier is too large");
- UMTX_UNLOCK(&b->b_lock);
- do {
- error = _thread_suspend(curthread, NULL);
- if (error == EINTR) {
- /*
- * Make sure this thread wasn't released from
- * the barrier while it was handling the signal.
- */
- PTHREAD_LOCK(curthread);
- if ((curthread->flags & PTHREAD_FLAGS_BARR_REL) != 0) {
- curthread->flags &= ~PTHREAD_FLAGS_BARR_REL;
- PTHREAD_UNLOCK(curthread);
- error = 0;
- break;
- }
- PTHREAD_UNLOCK(curthread);
- }
- } while (error == EINTR);
- return (error);
+ return (ret);
}
OpenPOWER on IntegriCloud