Add code to support barrier synchronous object and implement

pthread_mutex_timedlock().

Reviewed by: deischen
This commit is contained in:
David Xu 2003-09-04 14:06:43 +00:00
parent cf669e5456
commit 2ab83179b5
14 changed files with 725 additions and 12 deletions

View File

@ -52,6 +52,7 @@
#define PTHREAD_KEYS_MAX 256
#define PTHREAD_STACK_MIN 1024
#define PTHREAD_THREADS_MAX ULONG_MAX
#define PTHREAD_BARRIER_SERIAL_THREAD -1
/*
* Flags for threads and thread attributes.
@ -95,6 +96,8 @@ struct pthread_mutex_attr;
struct pthread_once;
struct pthread_rwlock;
struct pthread_rwlockattr;
struct pthread_barrier;
struct pthread_barrier_attr;
/*
* Primitive system data type definitions required by P1003.1c.
@ -113,6 +116,8 @@ typedef int pthread_key_t;
typedef struct pthread_once pthread_once_t;
typedef struct pthread_rwlock *pthread_rwlock_t;
typedef struct pthread_rwlockattr *pthread_rwlockattr_t;
typedef struct pthread_barrier *pthread_barrier_t;
typedef struct pthread_barrierattr *pthread_barrierattr_t;
/*
* Additional type definitions:
@ -203,6 +208,15 @@ int pthread_attr_setguardsize(pthread_attr_t *, size_t);
int pthread_attr_setstack(pthread_attr_t *, void *, size_t);
int pthread_attr_setstackaddr(pthread_attr_t *, void *);
int pthread_attr_setdetachstate(pthread_attr_t *, int);
int pthread_barrier_destroy(pthread_barrier_t *);
int pthread_barrier_init(pthread_barrier_t *,
const pthread_barrierattr_t *, unsigned);
int pthread_barrier_wait(pthread_barrier_t *);
int pthread_barrierattr_destroy(pthread_barrierattr_t *);
int pthread_barrierattr_getpshared(const pthread_barrierattr_t *,
int *);
int pthread_barrierattr_init(pthread_barrierattr_t *);
int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int);
void pthread_cleanup_pop(int);
void pthread_cleanup_push(void (*) (void *), void *routine_arg);
int pthread_condattr_destroy(pthread_condattr_t *);
@ -236,6 +250,8 @@ int pthread_mutex_init(pthread_mutex_t *,
const pthread_mutexattr_t *);
int pthread_mutex_lock(pthread_mutex_t *);
int pthread_mutex_trylock(pthread_mutex_t *);
int pthread_mutex_timedlock(pthread_mutex_t *,
const struct timespec *);
int pthread_mutex_unlock(pthread_mutex_t *);
int pthread_once(pthread_once_t *, void (*) (void));
int pthread_rwlock_destroy(pthread_rwlock_t *);

View File

@ -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 \

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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:

View File

@ -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);
}

View File

@ -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.
*/

View File

@ -14,6 +14,7 @@ global:
__pthread_cond_wait;
__pthread_mutex_lock;
__pthread_mutex_trylock;
__pthread_mutex_timedlock;
__read;
__readv;
__select;
@ -26,6 +27,13 @@ global:
_nanosleep;
_pause;
_pselect;
_pthread_barrier_destroy;
_pthread_barrier_init;
_pthread_barrier_wait;
_pthread_barrierattr_destroy;
_pthread_barrierattr_getpshared;
_pthread_barrierattr_init;
_pthread_barrierattr_setpshared;
_pthread_attr_default;
_pthread_attr_destroy;
_pthread_attr_get_np;
@ -80,6 +88,7 @@ global:
_pthread_mutex_init;
_pthread_mutex_lock;
_pthread_mutex_setprioceiling;
_pthread_mutex_timedlock;
_pthread_mutex_trylock;
_pthread_mutex_unlock;
_pthread_mutexattr_default;
@ -162,6 +171,13 @@ global:
pause;
poll;
pselect;
pthread_barrier_destroy;
pthread_barrier_init;
pthread_barrier_wait;
pthread_barrierattr_destroy;
pthread_barrierattr_getpshared;
pthread_barrierattr_init;
pthread_barrierattr_setpshared;
pthread_attr_destroy;
pthread_attr_get_np;
pthread_attr_getdetachstate;
@ -214,6 +230,7 @@ global:
pthread_mutex_init;
pthread_mutex_lock;
pthread_mutex_setprioceiling;
pthread_mutex_timedlock;
pthread_mutex_trylock;
pthread_mutex_unlock;
pthread_mutexattr_destroy;

View File

@ -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 \

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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:

View File

@ -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);
}

View File

@ -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.
*/