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
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=119736
14 changed files with 725 additions and 12 deletions

View File

@ -52,6 +52,7 @@
#define PTHREAD_KEYS_MAX 256 #define PTHREAD_KEYS_MAX 256
#define PTHREAD_STACK_MIN 1024 #define PTHREAD_STACK_MIN 1024
#define PTHREAD_THREADS_MAX ULONG_MAX #define PTHREAD_THREADS_MAX ULONG_MAX
#define PTHREAD_BARRIER_SERIAL_THREAD -1
/* /*
* Flags for threads and thread attributes. * Flags for threads and thread attributes.
@ -95,6 +96,8 @@ struct pthread_mutex_attr;
struct pthread_once; struct pthread_once;
struct pthread_rwlock; struct pthread_rwlock;
struct pthread_rwlockattr; struct pthread_rwlockattr;
struct pthread_barrier;
struct pthread_barrier_attr;
/* /*
* Primitive system data type definitions required by P1003.1c. * 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_once pthread_once_t;
typedef struct pthread_rwlock *pthread_rwlock_t; typedef struct pthread_rwlock *pthread_rwlock_t;
typedef struct pthread_rwlockattr *pthread_rwlockattr_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: * 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_setstack(pthread_attr_t *, void *, size_t);
int pthread_attr_setstackaddr(pthread_attr_t *, void *); int pthread_attr_setstackaddr(pthread_attr_t *, void *);
int pthread_attr_setdetachstate(pthread_attr_t *, int); 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_pop(int);
void pthread_cleanup_push(void (*) (void *), void *routine_arg); void pthread_cleanup_push(void (*) (void *), void *routine_arg);
int pthread_condattr_destroy(pthread_condattr_t *); int pthread_condattr_destroy(pthread_condattr_t *);
@ -236,6 +250,8 @@ int pthread_mutex_init(pthread_mutex_t *,
const pthread_mutexattr_t *); const pthread_mutexattr_t *);
int pthread_mutex_lock(pthread_mutex_t *); int pthread_mutex_lock(pthread_mutex_t *);
int pthread_mutex_trylock(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_mutex_unlock(pthread_mutex_t *);
int pthread_once(pthread_once_t *, void (*) (void)); int pthread_once(pthread_once_t *, void (*) (void));
int pthread_rwlock_destroy(pthread_rwlock_t *); int pthread_rwlock_destroy(pthread_rwlock_t *);

View File

@ -28,6 +28,8 @@ SRCS+= \
thr_attr_setstack.c \ thr_attr_setstack.c \
thr_attr_setstackaddr.c \ thr_attr_setstackaddr.c \
thr_attr_setstacksize.c \ thr_attr_setstacksize.c \
thr_barrier.c \
thr_barrierattr.c \
thr_cancel.c \ thr_cancel.c \
thr_clean.c \ thr_clean.c \
thr_close.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; curthread->wakeup_time.tv_nsec = -1;
break; break;
case PS_JOIN:
case PS_MUTEX_WAIT: case PS_MUTEX_WAIT:
break;
case PS_JOIN:
case PS_SUSPENDED: case PS_SUSPENDED:
case PS_DEADLOCK: case PS_DEADLOCK:
default: default:
@ -1735,8 +1736,10 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
case PS_SIGWAIT: case PS_SIGWAIT:
KSE_WAITQ_INSERT(kse, thread); KSE_WAITQ_INSERT(kse, thread);
break; break;
case PS_JOIN:
case PS_MUTEX_WAIT: case PS_MUTEX_WAIT:
KSE_WAITQ_INSERT(kse, thread);
break;
case PS_JOIN:
case PS_SIGSUSPEND: case PS_SIGSUSPEND:
case PS_SUSPENDED: case PS_SUSPENDED:
case PS_DEADLOCK: case PS_DEADLOCK:

View File

@ -64,6 +64,8 @@
#define THR_ASSERT_NOT_IN_SYNCQ(thr) #define THR_ASSERT_NOT_IN_SYNCQ(thr)
#endif #endif
#define THR_IN_MUTEXQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
/* /*
* Prototypes * Prototypes
*/ */
@ -86,6 +88,7 @@ static pthread_mutexattr_t static_mattr = &static_mutex_attr;
/* Single underscore versions provided for libc internal usage: */ /* Single underscore versions provided for libc internal usage: */
__weak_reference(__pthread_mutex_lock, pthread_mutex_lock); __weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
__weak_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock); __weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
/* No difference between libc and application usage of these: */ /* No difference between libc and application usage of these: */
@ -448,15 +451,22 @@ _pthread_mutex_trylock(pthread_mutex_t *mutex)
} }
static int 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; int ret = 0;
THR_ASSERT((m != NULL) && (*m != NULL), THR_ASSERT((m != NULL) && (*m != NULL),
"Uninitialized mutex in pthread_mutex_trylock_basic"); "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: */ /* Reset the interrupted flag: */
curthread->interrupted = 0; curthread->interrupted = 0;
curthread->timeout = 0;
curthread->wakeup_time.tv_sec = -1;
/* /*
* Enter a loop waiting to become the mutex owner. We need a * 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: */ /* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock); THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
} else { } 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 * Join the queue of threads waiting to lock
* the mutex and save a pointer to the mutex. * 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: */ /* Schedule the next thread: */
_thr_sched_switch(curthread); _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; break;
@ -560,6 +585,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Unlock the mutex structure: */ /* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock); THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
} else { } 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 * Join the queue of threads waiting to lock
* the mutex and save a pointer to the mutex. * 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: */ /* Schedule the next thread: */
_thr_sched_switch(curthread); _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; break;
@ -634,6 +674,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Unlock the mutex structure: */ /* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock); THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
} else { } 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 * Join the queue of threads waiting to lock
* the mutex and save a pointer to the mutex. * 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: */ /* Schedule the next thread: */
_thr_sched_switch(curthread); _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 * The threads priority may have changed while
* waiting for the mutex causing a ceiling * 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) && } 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 * Check to see if this thread was interrupted and
@ -720,7 +779,7 @@ __pthread_mutex_lock(pthread_mutex_t *m)
* initialization: * initialization:
*/ */
else if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0)) 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); return (ret);
} }
@ -746,7 +805,56 @@ _pthread_mutex_lock(pthread_mutex_t *m)
*/ */
else if ((*m != NULL) || else if ((*m != NULL) ||
((ret = init_static_private(curthread, m)) == 0)) ((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); return (ret);
} }

View File

@ -390,6 +390,18 @@ struct pthread_cond_attr {
long c_flags; 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. * Flags for condition variables.
*/ */

View File

@ -14,6 +14,7 @@ global:
__pthread_cond_wait; __pthread_cond_wait;
__pthread_mutex_lock; __pthread_mutex_lock;
__pthread_mutex_trylock; __pthread_mutex_trylock;
__pthread_mutex_timedlock;
__read; __read;
__readv; __readv;
__select; __select;
@ -26,6 +27,13 @@ global:
_nanosleep; _nanosleep;
_pause; _pause;
_pselect; _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_default;
_pthread_attr_destroy; _pthread_attr_destroy;
_pthread_attr_get_np; _pthread_attr_get_np;
@ -80,6 +88,7 @@ global:
_pthread_mutex_init; _pthread_mutex_init;
_pthread_mutex_lock; _pthread_mutex_lock;
_pthread_mutex_setprioceiling; _pthread_mutex_setprioceiling;
_pthread_mutex_timedlock;
_pthread_mutex_trylock; _pthread_mutex_trylock;
_pthread_mutex_unlock; _pthread_mutex_unlock;
_pthread_mutexattr_default; _pthread_mutexattr_default;
@ -162,6 +171,13 @@ global:
pause; pause;
poll; poll;
pselect; 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_destroy;
pthread_attr_get_np; pthread_attr_get_np;
pthread_attr_getdetachstate; pthread_attr_getdetachstate;
@ -214,6 +230,7 @@ global:
pthread_mutex_init; pthread_mutex_init;
pthread_mutex_lock; pthread_mutex_lock;
pthread_mutex_setprioceiling; pthread_mutex_setprioceiling;
pthread_mutex_timedlock;
pthread_mutex_trylock; pthread_mutex_trylock;
pthread_mutex_unlock; pthread_mutex_unlock;
pthread_mutexattr_destroy; pthread_mutexattr_destroy;

View File

@ -28,6 +28,8 @@ SRCS+= \
thr_attr_setstack.c \ thr_attr_setstack.c \
thr_attr_setstackaddr.c \ thr_attr_setstackaddr.c \
thr_attr_setstacksize.c \ thr_attr_setstacksize.c \
thr_barrier.c \
thr_barrierattr.c \
thr_cancel.c \ thr_cancel.c \
thr_clean.c \ thr_clean.c \
thr_close.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; curthread->wakeup_time.tv_nsec = -1;
break; break;
case PS_JOIN:
case PS_MUTEX_WAIT: case PS_MUTEX_WAIT:
break;
case PS_JOIN:
case PS_SUSPENDED: case PS_SUSPENDED:
case PS_DEADLOCK: case PS_DEADLOCK:
default: default:
@ -1735,8 +1736,10 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
case PS_SIGWAIT: case PS_SIGWAIT:
KSE_WAITQ_INSERT(kse, thread); KSE_WAITQ_INSERT(kse, thread);
break; break;
case PS_JOIN:
case PS_MUTEX_WAIT: case PS_MUTEX_WAIT:
KSE_WAITQ_INSERT(kse, thread);
break;
case PS_JOIN:
case PS_SIGSUSPEND: case PS_SIGSUSPEND:
case PS_SUSPENDED: case PS_SUSPENDED:
case PS_DEADLOCK: case PS_DEADLOCK:

View File

@ -64,6 +64,8 @@
#define THR_ASSERT_NOT_IN_SYNCQ(thr) #define THR_ASSERT_NOT_IN_SYNCQ(thr)
#endif #endif
#define THR_IN_MUTEXQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
/* /*
* Prototypes * Prototypes
*/ */
@ -86,6 +88,7 @@ static pthread_mutexattr_t static_mattr = &static_mutex_attr;
/* Single underscore versions provided for libc internal usage: */ /* Single underscore versions provided for libc internal usage: */
__weak_reference(__pthread_mutex_lock, pthread_mutex_lock); __weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
__weak_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock); __weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
/* No difference between libc and application usage of these: */ /* No difference between libc and application usage of these: */
@ -448,15 +451,22 @@ _pthread_mutex_trylock(pthread_mutex_t *mutex)
} }
static int 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; int ret = 0;
THR_ASSERT((m != NULL) && (*m != NULL), THR_ASSERT((m != NULL) && (*m != NULL),
"Uninitialized mutex in pthread_mutex_trylock_basic"); "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: */ /* Reset the interrupted flag: */
curthread->interrupted = 0; curthread->interrupted = 0;
curthread->timeout = 0;
curthread->wakeup_time.tv_sec = -1;
/* /*
* Enter a loop waiting to become the mutex owner. We need a * 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: */ /* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock); THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
} else { } 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 * Join the queue of threads waiting to lock
* the mutex and save a pointer to the mutex. * 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: */ /* Schedule the next thread: */
_thr_sched_switch(curthread); _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; break;
@ -560,6 +585,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Unlock the mutex structure: */ /* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock); THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
} else { } 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 * Join the queue of threads waiting to lock
* the mutex and save a pointer to the mutex. * 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: */ /* Schedule the next thread: */
_thr_sched_switch(curthread); _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; break;
@ -634,6 +674,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Unlock the mutex structure: */ /* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock); THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
} else { } 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 * Join the queue of threads waiting to lock
* the mutex and save a pointer to the mutex. * 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: */ /* Schedule the next thread: */
_thr_sched_switch(curthread); _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 * The threads priority may have changed while
* waiting for the mutex causing a ceiling * 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) && } 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 * Check to see if this thread was interrupted and
@ -720,7 +779,7 @@ __pthread_mutex_lock(pthread_mutex_t *m)
* initialization: * initialization:
*/ */
else if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0)) 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); return (ret);
} }
@ -746,7 +805,56 @@ _pthread_mutex_lock(pthread_mutex_t *m)
*/ */
else if ((*m != NULL) || else if ((*m != NULL) ||
((ret = init_static_private(curthread, m)) == 0)) ((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); return (ret);
} }

View File

@ -390,6 +390,18 @@ struct pthread_cond_attr {
long c_flags; 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. * Flags for condition variables.
*/ */