Add code to support barrier synchronous object and implement
pthread_mutex_timedlock(). Reviewed by: deischen
This commit is contained in:
parent
cf669e5456
commit
2ab83179b5
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=119736
@ -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 *);
|
||||||
|
@ -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 \
|
||||||
|
122
lib/libkse/thread/thr_barrier.c
Normal file
122
lib/libkse/thread/thr_barrier.c
Normal 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);
|
||||||
|
}
|
93
lib/libkse/thread/thr_barrierattr.c
Normal file
93
lib/libkse/thread/thr_barrierattr.c
Normal 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);
|
||||||
|
}
|
@ -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:
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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;
|
||||||
|
@ -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 \
|
||||||
|
122
lib/libpthread/thread/thr_barrier.c
Normal file
122
lib/libpthread/thread/thr_barrier.c
Normal 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);
|
||||||
|
}
|
93
lib/libpthread/thread/thr_barrierattr.c
Normal file
93
lib/libpthread/thread/thr_barrierattr.c
Normal 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);
|
||||||
|
}
|
@ -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:
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user