From 92fa0888006446f19ecb94917fc328f73a181ca5 Mon Sep 17 00:00:00 2001 From: mtm Date: Thu, 19 Feb 2004 13:51:52 +0000 Subject: Implement PThreads barriers and barrier attributes. --- lib/libthr/thread/Makefile.inc | 2 + lib/libthr/thread/thr_barrier.c | 129 ++++++++++++++++++++++++++++++++++++ lib/libthr/thread/thr_barrierattr.c | 79 ++++++++++++++++++++++ lib/libthr/thread/thr_cancel.c | 1 + lib/libthr/thread/thr_private.h | 19 +++++- lib/libthr/thread/thr_sig.c | 7 ++ 6 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 lib/libthr/thread/thr_barrier.c create mode 100644 lib/libthr/thread/thr_barrierattr.c (limited to 'lib/libthr') diff --git a/lib/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc index c43737e..8e11911 100644 --- a/lib/libthr/thread/Makefile.inc +++ b/lib/libthr/thread/Makefile.inc @@ -6,6 +6,8 @@ SRCS+= \ thr_attr.c \ thr_autoinit.c \ + thr_barrier.c \ + thr_barrierattr.c \ thr_cancel.c \ thr_clean.c \ thr_concurrency.c \ diff --git a/lib/libthr/thread/thr_barrier.c b/lib/libthr/thread/thr_barrier.c new file mode 100644 index 0000000..c635820 --- /dev/null +++ b/lib/libthr/thread/thr_barrier.c @@ -0,0 +1,129 @@ +/*- + * Copyright (c) 2004 Michael Telahun Makonnen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include + +#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); + +int +_pthread_barrier_destroy(pthread_barrier_t *barrier) +{ + if (*barrier == NULL) + return (EINVAL); + if ((*barrier)->b_subtotal > 0) + return (EBUSY); + PTHREAD_ASSERT((*barrier)->b_subtotal == 0, + "barrier count must be zero when destroyed"); + free(*barrier); + *barrier = NULL; + return (0); +} + +int +_pthread_barrier_init(pthread_barrier_t *barrier, + const pthread_barrierattr_t attr, unsigned int count) +{ + if (count < 1) + return (EINVAL); + *barrier = + (struct pthread_barrier *)malloc(sizeof(struct pthread_barrier)); + if (*barrier == NULL) + return (ENOMEM); + memset((void *)*barrier, 0, sizeof(struct pthread_barrier)); + (*barrier)->b_total = count; + TAILQ_INIT(&(*barrier)->b_barrq); + return (0); +} + +int +_pthread_barrier_wait(pthread_barrier_t *barrier) +{ + struct pthread_barrier *b; + struct pthread *ptd; + int error; + + if (*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) { + _thread_critical_enter(ptd); + PTHREAD_NEW_STATE(ptd, PS_RUNNING); + TAILQ_REMOVE(&b->b_barrq, ptd, sqe); + ptd->flags |= PTHREAD_FLAGS_BARR_REL; + _thread_critical_exit(ptd); + } + b->b_subtotal = 0; + UMTX_UNLOCK(&b->b_lock); + return (PTHREAD_BARRIER_SERIAL_THREAD); + } + + /* + * More threads need to reach the barrier. Suspend this thread. + */ + _thread_critical_enter(curthread); + TAILQ_INSERT_HEAD(&b->b_barrq, curthread, sqe); + PTHREAD_NEW_STATE(curthread, PS_BARRIER_WAIT); + _thread_critical_exit(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. + */ + _thread_critical_enter(curthread); + if ((curthread->flags & PTHREAD_FLAGS_BARR_REL) != 0) { + curthread->flags &= ~PTHREAD_FLAGS_BARR_REL; + _thread_critical_exit(curthread); + error = 0; + break; + } + PTHREAD_NEW_STATE(curthread, PS_BARRIER_WAIT); + _thread_critical_exit(curthread); + } + } while (error == EINTR); + return (error); +} diff --git a/lib/libthr/thread/thr_barrierattr.c b/lib/libthr/thread/thr_barrierattr.c new file mode 100644 index 0000000..2fe3955 --- /dev/null +++ b/lib/libthr/thread/thr_barrierattr.c @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 2004 Michael Telahun Makonnen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include + +#include "thr_private.h" + +__weak_reference(_pthread_barrierattr_destroy, pthread_barrierattr_destroy); +__weak_reference(_pthread_barrierattr_init, pthread_barrierattr_init); +__weak_reference(_pthread_barrierattr_getpshared, + pthread_barrierattr_getpshared); +__weak_reference(_pthread_barrierattr_setpshared, + pthread_barrierattr_setpshared); + +int +_pthread_barrierattr_destroy(pthread_barrierattr_t *attr) +{ + if (*attr == NULL) + return (EINVAL); + free(*attr); + *attr = NULL; + return (0); +} + +int +_pthread_barrierattr_init(pthread_barrierattr_t *attr) +{ + *attr = + (pthread_barrierattr_t)malloc(sizeof(struct pthread_barrierattr)); + if ((*attr) == NULL) + return (ENOMEM); + (*attr)->ba_pshared = PTHREAD_PROCESS_PRIVATE; + return (0); +} + +int +_pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, int *pshared) +{ + if (*attr == NULL) + return (EINVAL); + *pshared = (*attr)->ba_pshared; + return (0); +} + +int +_pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) +{ + if (*attr == NULL || (pshared != PTHREAD_PROCESS_PRIVATE && + pshared != PTHREAD_PROCESS_SHARED)) + return (EINVAL); + (*attr)->ba_pshared = pshared; + return (0); +} diff --git a/lib/libthr/thread/thr_cancel.c b/lib/libthr/thread/thr_cancel.c index d27b4b3..a539de7 100644 --- a/lib/libthr/thread/thr_cancel.c +++ b/lib/libthr/thread/thr_cancel.c @@ -93,6 +93,7 @@ retry: PTHREAD_NEW_STATE(pthread, PS_RUNNING); break; + case PS_BARRIER_WAIT: case PS_MUTEX_WAIT: case PS_COND_WAIT: /* diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h index cad1d04..e42bb14 100644 --- a/lib/libthr/thread/thr_private.h +++ b/lib/libthr/thread/thr_private.h @@ -146,7 +146,6 @@ PTHREAD_SET_STATE(thrd, newstate); \ } while (0) - /* * TailQ initialization values. */ @@ -368,6 +367,22 @@ extern int _pthread_page_size; */ #define GET_CURRENT_TOD(tv) gettimeofday(&(tv), NULL) +struct pthread_barrierattr { + int ba_pshared; +}; + +/* + * POSIX Threads barrier object. + * Lock order: + * 1. pthread_barrier + * 2. pthread + */ +struct pthread_barrier { + TAILQ_HEAD(barrq_head, pthread) b_barrq; + struct umtx b_lock; + int b_total; + int b_subtotal; +}; struct pthread_rwlockattr { int pshared; @@ -388,6 +403,7 @@ enum pthread_state { PS_RUNNING, PS_MUTEX_WAIT, PS_COND_WAIT, + PS_BARRIER_WAIT, PS_SLEEP_WAIT, /* XXX We need to wrap syscalls to set this state */ PS_WAIT_WAIT, PS_JOIN, @@ -535,6 +551,7 @@ struct pthread { int flags; #define PTHREAD_FLAGS_PRIVATE 0x0001 #define PTHREAD_EXITING 0x0002 +#define PTHREAD_FLAGS_BARR_REL 0x0004 /* has been released from barrier */ #define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/ #define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */ #define PTHREAD_FLAGS_SUSPENDED 0x0200 /* thread is suspended */ diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c index 0b8ba2b..771afbc 100644 --- a/lib/libthr/thread/thr_sig.c +++ b/lib/libthr/thread/thr_sig.c @@ -130,6 +130,13 @@ _thread_sig_wrapper(int sig, siginfo_t *info, void *context) * after cleanup handling. */ switch (curthread->state) { + case PS_BARRIER_WAIT: + /* + * XXX - The thread has reached the barrier. We can't + * "back it away" from the barrier. + */ + _thread_critical_enter(curthread); + break; case PS_COND_WAIT: /* * Cache the address, since it will not be available -- cgit v1.1