diff options
author | davidxu <davidxu@FreeBSD.org> | 2003-09-04 14:06:43 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2003-09-04 14:06:43 +0000 |
commit | 82aeb9fc856d7c45903f5b5a6a613167c959ac57 (patch) | |
tree | d27b2604ed10f911d9b2dbba4508f40514b74820 /lib/libkse | |
parent | a07778264c85df6f9c919bd824594eb6646ac3b9 (diff) | |
download | FreeBSD-src-82aeb9fc856d7c45903f5b5a6a613167c959ac57.zip FreeBSD-src-82aeb9fc856d7c45903f5b5a6a613167c959ac57.tar.gz |
Add code to support barrier synchronous object and implement
pthread_mutex_timedlock().
Reviewed by: deischen
Diffstat (limited to 'lib/libkse')
-rw-r--r-- | lib/libkse/thread/Makefile.inc | 2 | ||||
-rw-r--r-- | lib/libkse/thread/thr_barrier.c | 122 | ||||
-rw-r--r-- | lib/libkse/thread/thr_barrierattr.c | 93 | ||||
-rw-r--r-- | lib/libkse/thread/thr_kern.c | 7 | ||||
-rw-r--r-- | lib/libkse/thread/thr_mutex.c | 116 | ||||
-rw-r--r-- | lib/libkse/thread/thr_private.h | 12 |
6 files changed, 346 insertions, 6 deletions
diff --git a/lib/libkse/thread/Makefile.inc b/lib/libkse/thread/Makefile.inc index 328c3c8..70f88cd 100644 --- a/lib/libkse/thread/Makefile.inc +++ b/lib/libkse/thread/Makefile.inc @@ -28,6 +28,8 @@ SRCS+= \ thr_attr_setstack.c \ thr_attr_setstackaddr.c \ thr_attr_setstacksize.c \ + thr_barrier.c \ + thr_barrierattr.c \ thr_cancel.c \ thr_clean.c \ thr_close.c \ diff --git a/lib/libkse/thread/thr_barrier.c b/lib/libkse/thread/thr_barrier.c new file mode 100644 index 0000000..612acb1 --- /dev/null +++ b/lib/libkse/thread/thr_barrier.c @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 2003 David Xu <davidxu@freebsd.org> + * 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 <errno.h> +#include <stdlib.h> +#include "namespace.h" +#include <pthread.h> +#include "un-namespace.h" +#include "thr_private.h" + +__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) +{ + pthread_barrier_t bar; + int ret, ret2; + + if (barrier == NULL || *barrier == NULL) + return (EINVAL); + + bar = *barrier; + if (bar->b_waiters > 0) + return (EBUSY); + *barrier = NULL; + ret = _pthread_mutex_destroy(&bar->b_lock); + ret2 = _pthread_cond_destroy(&bar->b_cond); + free(bar); + return (ret ? ret : ret2); +} + +int +_pthread_barrier_init(pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, int count) +{ + pthread_barrier_t bar; + int ret; + + if (barrier == NULL || count <= 0) + return (EINVAL); + + bar = malloc(sizeof(struct pthread_barrier)); + if (bar == NULL) + return (ENOMEM); + + if ((ret = _pthread_mutex_init(&bar->b_lock, NULL)) != 0) { + free(bar); + return (ret); + } + + if ((ret = _pthread_cond_init(&bar->b_cond, NULL)) != 0) { + _pthread_mutex_destroy(&bar->b_lock); + free(bar); + return (ret); + } + + bar->b_waiters = 0; + bar->b_count = count; + bar->b_generation = 0; + *barrier = bar; + + return (0); +} + +int +_pthread_barrier_wait(pthread_barrier_t *barrier) +{ + int ret, gen; + pthread_barrier_t bar; + + if (barrier == NULL || *barrier == NULL) + return (EINVAL); + + bar = *barrier; + if ((ret = _pthread_mutex_lock(&bar->b_lock)) != 0) + return (ret); + + if (++bar->b_waiters == bar->b_count) { + /* Current thread is lastest thread */ + bar->b_generation++; + bar->b_waiters = 0; + ret = _pthread_cond_broadcast(&bar->b_cond); + if (ret == 0) + ret = PTHREAD_BARRIER_SERIAL_THREAD; + } else { + gen = bar->b_generation; + do { + ret = _pthread_cond_wait( + &bar->b_cond, &bar->b_lock); + /* test generation to avoid bogus wakeup */ + } while (ret == 0 && gen == bar->b_generation); + } + _pthread_mutex_unlock(&bar->b_lock); + return (ret); +} diff --git a/lib/libkse/thread/thr_barrierattr.c b/lib/libkse/thread/thr_barrierattr.c new file mode 100644 index 0000000..f71c0dd --- /dev/null +++ b/lib/libkse/thread/thr_barrierattr.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2003 David Xu <davidxu@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), 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 COPYRIGHT HOLDER(S) ``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 COPYRIGHT HOLDER(S) 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 <errno.h> +#include <stdlib.h> +#include <pthread.h> +#include "thr_private.h" + +__weak_reference(_pthread_barrierattr_destroy, pthread_barrierattr_destroy); +__weak_reference(_pthread_barrierattr_init, pthread_barrierattr_init); +__weak_reference(_pthread_barrierattr_setpshared, + pthread_barrierattr_setpshared); +__weak_reference(_pthread_barrierattr_getpshared, + pthread_barrierattr_getpshared); + +int +_pthread_barrierattr_destroy(pthread_barrierattr_t *attr) +{ + + if (attr == NULL || *attr == NULL) + return (EINVAL); + + free(*attr); + return (0); +} + +int +_pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr, + int *pshared) +{ + + if (attr == NULL || *attr == NULL) + return (EINVAL); + + *pshared = (*attr)->pshared; + return (0); +} + +int +_pthread_barrierattr_init(pthread_barrierattr_t *attr) +{ + + if (attr == NULL) + return (EINVAL); + + if ((*attr = malloc(sizeof(struct pthread_barrierattr))) == NULL) + return (ENOMEM); + + (*attr)->pshared = PTHREAD_PROCESS_PRIVATE; + return (0); +} + +int +_pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared) +{ + + if (attr == NULL || *attr == NULL) + return (EINVAL); + + /* Only PTHREAD_PROCESS_PRIVATE is supported. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return (EINVAL); + + (*attr)->pshared = pshared; + return (0); +} diff --git a/lib/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c index 5ed144a..4d308c3 100644 --- a/lib/libkse/thread/thr_kern.c +++ b/lib/libkse/thread/thr_kern.c @@ -853,8 +853,9 @@ kse_sched_single(struct kse_mailbox *kmbx) curthread->wakeup_time.tv_nsec = -1; break; - case PS_JOIN: case PS_MUTEX_WAIT: + break; + case PS_JOIN: case PS_SUSPENDED: case PS_DEADLOCK: default: @@ -1735,8 +1736,10 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread) case PS_SIGWAIT: KSE_WAITQ_INSERT(kse, thread); break; - case PS_JOIN: case PS_MUTEX_WAIT: + KSE_WAITQ_INSERT(kse, thread); + break; + case PS_JOIN: case PS_SIGSUSPEND: case PS_SUSPENDED: case PS_DEADLOCK: diff --git a/lib/libkse/thread/thr_mutex.c b/lib/libkse/thread/thr_mutex.c index 00da0f0..177a296 100644 --- a/lib/libkse/thread/thr_mutex.c +++ b/lib/libkse/thread/thr_mutex.c @@ -64,6 +64,8 @@ #define THR_ASSERT_NOT_IN_SYNCQ(thr) #endif +#define THR_IN_MUTEXQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0) + /* * Prototypes */ @@ -86,6 +88,7 @@ static pthread_mutexattr_t static_mattr = &static_mutex_attr; /* Single underscore versions provided for libc internal usage: */ __weak_reference(__pthread_mutex_lock, pthread_mutex_lock); +__weak_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock); __weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock); /* No difference between libc and application usage of these: */ @@ -448,15 +451,22 @@ _pthread_mutex_trylock(pthread_mutex_t *mutex) } static int -mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m) +mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m, + const struct timespec * abstime) { int ret = 0; THR_ASSERT((m != NULL) && (*m != NULL), "Uninitialized mutex in pthread_mutex_trylock_basic"); + if (abstime != NULL && (abstime->tv_sec < 0 || abstime->tv_nsec < 0 || + abstime->tv_nsec >= 1000000000)) + return (EINVAL); + /* Reset the interrupted flag: */ curthread->interrupted = 0; + curthread->timeout = 0; + curthread->wakeup_time.tv_sec = -1; /* * Enter a loop waiting to become the mutex owner. We need a @@ -501,6 +511,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m) /* Unlock the mutex structure: */ THR_LOCK_RELEASE(curthread, &(*m)->m_lock); } else { + /* Set the wakeup time: */ + if (abstime) { + curthread->wakeup_time.tv_sec = + abstime->tv_sec; + curthread->wakeup_time.tv_nsec = + abstime->tv_nsec; + } + /* * Join the queue of threads waiting to lock * the mutex and save a pointer to the mutex. @@ -521,6 +539,13 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m) /* Schedule the next thread: */ _thr_sched_switch(curthread); + + if (THR_IN_MUTEXQ(curthread)) { + THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock); + mutex_queue_remove(*m, curthread); + curthread->data.mutex = NULL; + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + } } break; @@ -560,6 +585,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m) /* Unlock the mutex structure: */ THR_LOCK_RELEASE(curthread, &(*m)->m_lock); } else { + /* Set the wakeup time: */ + if (abstime) { + curthread->wakeup_time.tv_sec = + abstime->tv_sec; + curthread->wakeup_time.tv_nsec = + abstime->tv_nsec; + } + /* * Join the queue of threads waiting to lock * the mutex and save a pointer to the mutex. @@ -585,6 +618,13 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m) /* Schedule the next thread: */ _thr_sched_switch(curthread); + + if (THR_IN_MUTEXQ(curthread)) { + THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock); + mutex_queue_remove(*m, curthread); + curthread->data.mutex = NULL; + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + } } break; @@ -634,6 +674,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m) /* Unlock the mutex structure: */ THR_LOCK_RELEASE(curthread, &(*m)->m_lock); } else { + /* Set the wakeup time: */ + if (abstime) { + curthread->wakeup_time.tv_sec = + abstime->tv_sec; + curthread->wakeup_time.tv_nsec = + abstime->tv_nsec; + } + /* * Join the queue of threads waiting to lock * the mutex and save a pointer to the mutex. @@ -659,6 +707,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m) /* Schedule the next thread: */ _thr_sched_switch(curthread); + + if (THR_IN_MUTEXQ(curthread)) { + THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock); + mutex_queue_remove(*m, curthread); + curthread->data.mutex = NULL; + THR_LOCK_RELEASE(curthread, &(*m)->m_lock); + } + /* * The threads priority may have changed while * waiting for the mutex causing a ceiling @@ -680,7 +736,10 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m) } } while (((*m)->m_owner != curthread) && (ret == 0) && - (curthread->interrupted == 0)); + (curthread->interrupted == 0) && (curthread->timeout == 0)); + + if (ret == 0 && curthread->timeout) + ret = ETIMEDOUT; /* * Check to see if this thread was interrupted and @@ -720,7 +779,7 @@ __pthread_mutex_lock(pthread_mutex_t *m) * initialization: */ else if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0)) - ret = mutex_lock_common(curthread, m); + ret = mutex_lock_common(curthread, m, NULL); return (ret); } @@ -746,7 +805,56 @@ _pthread_mutex_lock(pthread_mutex_t *m) */ else if ((*m != NULL) || ((ret = init_static_private(curthread, m)) == 0)) - ret = mutex_lock_common(curthread, m); + ret = mutex_lock_common(curthread, m, NULL); + + return (ret); +} + +int +__pthread_mutex_timedlock(pthread_mutex_t *m, + const struct timespec *abs_timeout) +{ + struct pthread *curthread; + int ret = 0; + + if (_thr_initial == NULL) + _libpthread_init(NULL); + + curthread = _get_curthread(); + if (m == NULL) + ret = EINVAL; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + else if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0)) + ret = mutex_lock_common(curthread, m, abs_timeout); + + return (ret); +} + +int +_pthread_mutex_timedlock(pthread_mutex_t *m, + const struct timespec *abs_timeout) +{ + struct pthread *curthread; + int ret = 0; + + if (_thr_initial == NULL) + _libpthread_init(NULL); + curthread = _get_curthread(); + + if (m == NULL) + ret = EINVAL; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization marking it private (delete safe): + */ + else if ((*m != NULL) || + ((ret = init_static_private(curthread, m)) == 0)) + ret = mutex_lock_common(curthread, m, abs_timeout); return (ret); } diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h index 6302299..2127619 100644 --- a/lib/libkse/thread/thr_private.h +++ b/lib/libkse/thread/thr_private.h @@ -390,6 +390,18 @@ struct pthread_cond_attr { long c_flags; }; +struct pthread_barrier { + pthread_mutex_t b_lock; + pthread_cond_t b_cond; + int b_count; + int b_waiters; + int b_generation; +}; + +struct pthread_barrierattr { + int pshared; +}; + /* * Flags for condition variables. */ |