summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/pthread.h16
-rw-r--r--lib/libkse/thread/Makefile.inc2
-rw-r--r--lib/libkse/thread/thr_barrier.c122
-rw-r--r--lib/libkse/thread/thr_barrierattr.c93
-rw-r--r--lib/libkse/thread/thr_kern.c7
-rw-r--r--lib/libkse/thread/thr_mutex.c116
-rw-r--r--lib/libkse/thread/thr_private.h12
-rw-r--r--lib/libpthread/pthread.map17
-rw-r--r--lib/libpthread/thread/Makefile.inc2
-rw-r--r--lib/libpthread/thread/thr_barrier.c122
-rw-r--r--lib/libpthread/thread/thr_barrierattr.c93
-rw-r--r--lib/libpthread/thread/thr_kern.c7
-rw-r--r--lib/libpthread/thread/thr_mutex.c116
-rw-r--r--lib/libpthread/thread/thr_private.h12
14 files changed, 725 insertions, 12 deletions
diff --git a/include/pthread.h b/include/pthread.h
index 2ac07e0..9da2412 100644
--- a/include/pthread.h
+++ b/include/pthread.h
@@ -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 *);
diff --git a/lib/libkse/thread/Makefile.inc b/lib/libkse/thread/Makefile.inc
index 328c3c8..70f88cd 100644
--- a/lib/libkse/thread/Makefile.inc
+++ b/lib/libkse/thread/Makefile.inc
@@ -28,6 +28,8 @@ SRCS+= \
thr_attr_setstack.c \
thr_attr_setstackaddr.c \
thr_attr_setstacksize.c \
+ thr_barrier.c \
+ thr_barrierattr.c \
thr_cancel.c \
thr_clean.c \
thr_close.c \
diff --git a/lib/libkse/thread/thr_barrier.c b/lib/libkse/thread/thr_barrier.c
new file mode 100644
index 0000000..612acb1
--- /dev/null
+++ b/lib/libkse/thread/thr_barrier.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2003 David Xu <davidxu@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+__weak_reference(_pthread_barrier_init, pthread_barrier_init);
+__weak_reference(_pthread_barrier_wait, pthread_barrier_wait);
+__weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy);
+
+int
+_pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+ pthread_barrier_t bar;
+ int ret, ret2;
+
+ if (barrier == NULL || *barrier == NULL)
+ return (EINVAL);
+
+ bar = *barrier;
+ if (bar->b_waiters > 0)
+ return (EBUSY);
+ *barrier = NULL;
+ ret = _pthread_mutex_destroy(&bar->b_lock);
+ ret2 = _pthread_cond_destroy(&bar->b_cond);
+ free(bar);
+ return (ret ? ret : ret2);
+}
+
+int
+_pthread_barrier_init(pthread_barrier_t *barrier,
+ const pthread_barrierattr_t *attr, int count)
+{
+ pthread_barrier_t bar;
+ int ret;
+
+ if (barrier == NULL || count <= 0)
+ return (EINVAL);
+
+ bar = malloc(sizeof(struct pthread_barrier));
+ if (bar == NULL)
+ return (ENOMEM);
+
+ if ((ret = _pthread_mutex_init(&bar->b_lock, NULL)) != 0) {
+ free(bar);
+ return (ret);
+ }
+
+ if ((ret = _pthread_cond_init(&bar->b_cond, NULL)) != 0) {
+ _pthread_mutex_destroy(&bar->b_lock);
+ free(bar);
+ return (ret);
+ }
+
+ bar->b_waiters = 0;
+ bar->b_count = count;
+ bar->b_generation = 0;
+ *barrier = bar;
+
+ return (0);
+}
+
+int
+_pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+ int ret, gen;
+ pthread_barrier_t bar;
+
+ if (barrier == NULL || *barrier == NULL)
+ return (EINVAL);
+
+ bar = *barrier;
+ if ((ret = _pthread_mutex_lock(&bar->b_lock)) != 0)
+ return (ret);
+
+ if (++bar->b_waiters == bar->b_count) {
+ /* Current thread is lastest thread */
+ bar->b_generation++;
+ bar->b_waiters = 0;
+ ret = _pthread_cond_broadcast(&bar->b_cond);
+ if (ret == 0)
+ ret = PTHREAD_BARRIER_SERIAL_THREAD;
+ } else {
+ gen = bar->b_generation;
+ do {
+ ret = _pthread_cond_wait(
+ &bar->b_cond, &bar->b_lock);
+ /* test generation to avoid bogus wakeup */
+ } while (ret == 0 && gen == bar->b_generation);
+ }
+ _pthread_mutex_unlock(&bar->b_lock);
+ return (ret);
+}
diff --git a/lib/libkse/thread/thr_barrierattr.c b/lib/libkse/thread/thr_barrierattr.c
new file mode 100644
index 0000000..f71c0dd
--- /dev/null
+++ b/lib/libkse/thread/thr_barrierattr.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2003 David Xu <davidxu@freebsd.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_barrierattr_destroy, pthread_barrierattr_destroy);
+__weak_reference(_pthread_barrierattr_init, pthread_barrierattr_init);
+__weak_reference(_pthread_barrierattr_setpshared,
+ pthread_barrierattr_setpshared);
+__weak_reference(_pthread_barrierattr_getpshared,
+ pthread_barrierattr_getpshared);
+
+int
+_pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ free(*attr);
+ return (0);
+}
+
+int
+_pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr,
+ int *pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ *pshared = (*attr)->pshared;
+ return (0);
+}
+
+int
+_pthread_barrierattr_init(pthread_barrierattr_t *attr)
+{
+
+ if (attr == NULL)
+ return (EINVAL);
+
+ if ((*attr = malloc(sizeof(struct pthread_barrierattr))) == NULL)
+ return (ENOMEM);
+
+ (*attr)->pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ /* Only PTHREAD_PROCESS_PRIVATE is supported. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+
+ (*attr)->pshared = pshared;
+ return (0);
+}
diff --git a/lib/libkse/thread/thr_kern.c b/lib/libkse/thread/thr_kern.c
index 5ed144a..4d308c3 100644
--- a/lib/libkse/thread/thr_kern.c
+++ b/lib/libkse/thread/thr_kern.c
@@ -853,8 +853,9 @@ kse_sched_single(struct kse_mailbox *kmbx)
curthread->wakeup_time.tv_nsec = -1;
break;
- case PS_JOIN:
case PS_MUTEX_WAIT:
+ break;
+ case PS_JOIN:
case PS_SUSPENDED:
case PS_DEADLOCK:
default:
@@ -1735,8 +1736,10 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
case PS_SIGWAIT:
KSE_WAITQ_INSERT(kse, thread);
break;
- case PS_JOIN:
case PS_MUTEX_WAIT:
+ KSE_WAITQ_INSERT(kse, thread);
+ break;
+ case PS_JOIN:
case PS_SIGSUSPEND:
case PS_SUSPENDED:
case PS_DEADLOCK:
diff --git a/lib/libkse/thread/thr_mutex.c b/lib/libkse/thread/thr_mutex.c
index 00da0f0..177a296 100644
--- a/lib/libkse/thread/thr_mutex.c
+++ b/lib/libkse/thread/thr_mutex.c
@@ -64,6 +64,8 @@
#define THR_ASSERT_NOT_IN_SYNCQ(thr)
#endif
+#define THR_IN_MUTEXQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
+
/*
* Prototypes
*/
@@ -86,6 +88,7 @@ static pthread_mutexattr_t static_mattr = &static_mutex_attr;
/* Single underscore versions provided for libc internal usage: */
__weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
+__weak_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
/* No difference between libc and application usage of these: */
@@ -448,15 +451,22 @@ _pthread_mutex_trylock(pthread_mutex_t *mutex)
}
static int
-mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
+mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
+ const struct timespec * abstime)
{
int ret = 0;
THR_ASSERT((m != NULL) && (*m != NULL),
"Uninitialized mutex in pthread_mutex_trylock_basic");
+ if (abstime != NULL && (abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000))
+ return (EINVAL);
+
/* Reset the interrupted flag: */
curthread->interrupted = 0;
+ curthread->timeout = 0;
+ curthread->wakeup_time.tv_sec = -1;
/*
* Enter a loop waiting to become the mutex owner. We need a
@@ -501,6 +511,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
} else {
+ /* Set the wakeup time: */
+ if (abstime) {
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ }
+
/*
* Join the queue of threads waiting to lock
* the mutex and save a pointer to the mutex.
@@ -521,6 +539,13 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Schedule the next thread: */
_thr_sched_switch(curthread);
+
+ if (THR_IN_MUTEXQ(curthread)) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ mutex_queue_remove(*m, curthread);
+ curthread->data.mutex = NULL;
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
}
break;
@@ -560,6 +585,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
} else {
+ /* Set the wakeup time: */
+ if (abstime) {
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ }
+
/*
* Join the queue of threads waiting to lock
* the mutex and save a pointer to the mutex.
@@ -585,6 +618,13 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Schedule the next thread: */
_thr_sched_switch(curthread);
+
+ if (THR_IN_MUTEXQ(curthread)) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ mutex_queue_remove(*m, curthread);
+ curthread->data.mutex = NULL;
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
}
break;
@@ -634,6 +674,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
} else {
+ /* Set the wakeup time: */
+ if (abstime) {
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ }
+
/*
* Join the queue of threads waiting to lock
* the mutex and save a pointer to the mutex.
@@ -659,6 +707,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Schedule the next thread: */
_thr_sched_switch(curthread);
+
+ if (THR_IN_MUTEXQ(curthread)) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ mutex_queue_remove(*m, curthread);
+ curthread->data.mutex = NULL;
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
+
/*
* The threads priority may have changed while
* waiting for the mutex causing a ceiling
@@ -680,7 +736,10 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
}
} while (((*m)->m_owner != curthread) && (ret == 0) &&
- (curthread->interrupted == 0));
+ (curthread->interrupted == 0) && (curthread->timeout == 0));
+
+ if (ret == 0 && curthread->timeout)
+ ret = ETIMEDOUT;
/*
* Check to see if this thread was interrupted and
@@ -720,7 +779,7 @@ __pthread_mutex_lock(pthread_mutex_t *m)
* initialization:
*/
else if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0))
- ret = mutex_lock_common(curthread, m);
+ ret = mutex_lock_common(curthread, m, NULL);
return (ret);
}
@@ -746,7 +805,56 @@ _pthread_mutex_lock(pthread_mutex_t *m)
*/
else if ((*m != NULL) ||
((ret = init_static_private(curthread, m)) == 0))
- ret = mutex_lock_common(curthread, m);
+ ret = mutex_lock_common(curthread, m, NULL);
+
+ return (ret);
+}
+
+int
+__pthread_mutex_timedlock(pthread_mutex_t *m,
+ const struct timespec *abs_timeout)
+{
+ struct pthread *curthread;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+
+ curthread = _get_curthread();
+ if (m == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ else if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0))
+ ret = mutex_lock_common(curthread, m, abs_timeout);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_timedlock(pthread_mutex_t *m,
+ const struct timespec *abs_timeout)
+{
+ struct pthread *curthread;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+ curthread = _get_curthread();
+
+ if (m == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ else if ((*m != NULL) ||
+ ((ret = init_static_private(curthread, m)) == 0))
+ ret = mutex_lock_common(curthread, m, abs_timeout);
return (ret);
}
diff --git a/lib/libkse/thread/thr_private.h b/lib/libkse/thread/thr_private.h
index 6302299..2127619 100644
--- a/lib/libkse/thread/thr_private.h
+++ b/lib/libkse/thread/thr_private.h
@@ -390,6 +390,18 @@ struct pthread_cond_attr {
long c_flags;
};
+struct pthread_barrier {
+ pthread_mutex_t b_lock;
+ pthread_cond_t b_cond;
+ int b_count;
+ int b_waiters;
+ int b_generation;
+};
+
+struct pthread_barrierattr {
+ int pshared;
+};
+
/*
* Flags for condition variables.
*/
diff --git a/lib/libpthread/pthread.map b/lib/libpthread/pthread.map
index a2f65a4..62f4635 100644
--- a/lib/libpthread/pthread.map
+++ b/lib/libpthread/pthread.map
@@ -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;
diff --git a/lib/libpthread/thread/Makefile.inc b/lib/libpthread/thread/Makefile.inc
index 328c3c8..70f88cd 100644
--- a/lib/libpthread/thread/Makefile.inc
+++ b/lib/libpthread/thread/Makefile.inc
@@ -28,6 +28,8 @@ SRCS+= \
thr_attr_setstack.c \
thr_attr_setstackaddr.c \
thr_attr_setstacksize.c \
+ thr_barrier.c \
+ thr_barrierattr.c \
thr_cancel.c \
thr_clean.c \
thr_close.c \
diff --git a/lib/libpthread/thread/thr_barrier.c b/lib/libpthread/thread/thr_barrier.c
new file mode 100644
index 0000000..612acb1
--- /dev/null
+++ b/lib/libpthread/thread/thr_barrier.c
@@ -0,0 +1,122 @@
+/*-
+ * Copyright (c) 2003 David Xu <davidxu@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include "namespace.h"
+#include <pthread.h>
+#include "un-namespace.h"
+#include "thr_private.h"
+
+__weak_reference(_pthread_barrier_init, pthread_barrier_init);
+__weak_reference(_pthread_barrier_wait, pthread_barrier_wait);
+__weak_reference(_pthread_barrier_destroy, pthread_barrier_destroy);
+
+int
+_pthread_barrier_destroy(pthread_barrier_t *barrier)
+{
+ pthread_barrier_t bar;
+ int ret, ret2;
+
+ if (barrier == NULL || *barrier == NULL)
+ return (EINVAL);
+
+ bar = *barrier;
+ if (bar->b_waiters > 0)
+ return (EBUSY);
+ *barrier = NULL;
+ ret = _pthread_mutex_destroy(&bar->b_lock);
+ ret2 = _pthread_cond_destroy(&bar->b_cond);
+ free(bar);
+ return (ret ? ret : ret2);
+}
+
+int
+_pthread_barrier_init(pthread_barrier_t *barrier,
+ const pthread_barrierattr_t *attr, int count)
+{
+ pthread_barrier_t bar;
+ int ret;
+
+ if (barrier == NULL || count <= 0)
+ return (EINVAL);
+
+ bar = malloc(sizeof(struct pthread_barrier));
+ if (bar == NULL)
+ return (ENOMEM);
+
+ if ((ret = _pthread_mutex_init(&bar->b_lock, NULL)) != 0) {
+ free(bar);
+ return (ret);
+ }
+
+ if ((ret = _pthread_cond_init(&bar->b_cond, NULL)) != 0) {
+ _pthread_mutex_destroy(&bar->b_lock);
+ free(bar);
+ return (ret);
+ }
+
+ bar->b_waiters = 0;
+ bar->b_count = count;
+ bar->b_generation = 0;
+ *barrier = bar;
+
+ return (0);
+}
+
+int
+_pthread_barrier_wait(pthread_barrier_t *barrier)
+{
+ int ret, gen;
+ pthread_barrier_t bar;
+
+ if (barrier == NULL || *barrier == NULL)
+ return (EINVAL);
+
+ bar = *barrier;
+ if ((ret = _pthread_mutex_lock(&bar->b_lock)) != 0)
+ return (ret);
+
+ if (++bar->b_waiters == bar->b_count) {
+ /* Current thread is lastest thread */
+ bar->b_generation++;
+ bar->b_waiters = 0;
+ ret = _pthread_cond_broadcast(&bar->b_cond);
+ if (ret == 0)
+ ret = PTHREAD_BARRIER_SERIAL_THREAD;
+ } else {
+ gen = bar->b_generation;
+ do {
+ ret = _pthread_cond_wait(
+ &bar->b_cond, &bar->b_lock);
+ /* test generation to avoid bogus wakeup */
+ } while (ret == 0 && gen == bar->b_generation);
+ }
+ _pthread_mutex_unlock(&bar->b_lock);
+ return (ret);
+}
diff --git a/lib/libpthread/thread/thr_barrierattr.c b/lib/libpthread/thread/thr_barrierattr.c
new file mode 100644
index 0000000..f71c0dd
--- /dev/null
+++ b/lib/libpthread/thread/thr_barrierattr.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2003 David Xu <davidxu@freebsd.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice(s), this list of conditions and the following disclaimer as
+ * the first lines of this file unmodified other than the possible
+ * addition of one or more copyright notices.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice(s), this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include "thr_private.h"
+
+__weak_reference(_pthread_barrierattr_destroy, pthread_barrierattr_destroy);
+__weak_reference(_pthread_barrierattr_init, pthread_barrierattr_init);
+__weak_reference(_pthread_barrierattr_setpshared,
+ pthread_barrierattr_setpshared);
+__weak_reference(_pthread_barrierattr_getpshared,
+ pthread_barrierattr_getpshared);
+
+int
+_pthread_barrierattr_destroy(pthread_barrierattr_t *attr)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ free(*attr);
+ return (0);
+}
+
+int
+_pthread_barrierattr_getpshared(const pthread_barrierattr_t *attr,
+ int *pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ *pshared = (*attr)->pshared;
+ return (0);
+}
+
+int
+_pthread_barrierattr_init(pthread_barrierattr_t *attr)
+{
+
+ if (attr == NULL)
+ return (EINVAL);
+
+ if ((*attr = malloc(sizeof(struct pthread_barrierattr))) == NULL)
+ return (ENOMEM);
+
+ (*attr)->pshared = PTHREAD_PROCESS_PRIVATE;
+ return (0);
+}
+
+int
+_pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared)
+{
+
+ if (attr == NULL || *attr == NULL)
+ return (EINVAL);
+
+ /* Only PTHREAD_PROCESS_PRIVATE is supported. */
+ if (pshared != PTHREAD_PROCESS_PRIVATE)
+ return (EINVAL);
+
+ (*attr)->pshared = pshared;
+ return (0);
+}
diff --git a/lib/libpthread/thread/thr_kern.c b/lib/libpthread/thread/thr_kern.c
index 5ed144a..4d308c3 100644
--- a/lib/libpthread/thread/thr_kern.c
+++ b/lib/libpthread/thread/thr_kern.c
@@ -853,8 +853,9 @@ kse_sched_single(struct kse_mailbox *kmbx)
curthread->wakeup_time.tv_nsec = -1;
break;
- case PS_JOIN:
case PS_MUTEX_WAIT:
+ break;
+ case PS_JOIN:
case PS_SUSPENDED:
case PS_DEADLOCK:
default:
@@ -1735,8 +1736,10 @@ kse_switchout_thread(struct kse *kse, struct pthread *thread)
case PS_SIGWAIT:
KSE_WAITQ_INSERT(kse, thread);
break;
- case PS_JOIN:
case PS_MUTEX_WAIT:
+ KSE_WAITQ_INSERT(kse, thread);
+ break;
+ case PS_JOIN:
case PS_SIGSUSPEND:
case PS_SUSPENDED:
case PS_DEADLOCK:
diff --git a/lib/libpthread/thread/thr_mutex.c b/lib/libpthread/thread/thr_mutex.c
index 00da0f0..177a296 100644
--- a/lib/libpthread/thread/thr_mutex.c
+++ b/lib/libpthread/thread/thr_mutex.c
@@ -64,6 +64,8 @@
#define THR_ASSERT_NOT_IN_SYNCQ(thr)
#endif
+#define THR_IN_MUTEXQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
+
/*
* Prototypes
*/
@@ -86,6 +88,7 @@ static pthread_mutexattr_t static_mattr = &static_mutex_attr;
/* Single underscore versions provided for libc internal usage: */
__weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
+__weak_reference(__pthread_mutex_timedlock, pthread_mutex_timedlock);
__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
/* No difference between libc and application usage of these: */
@@ -448,15 +451,22 @@ _pthread_mutex_trylock(pthread_mutex_t *mutex)
}
static int
-mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
+mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m,
+ const struct timespec * abstime)
{
int ret = 0;
THR_ASSERT((m != NULL) && (*m != NULL),
"Uninitialized mutex in pthread_mutex_trylock_basic");
+ if (abstime != NULL && (abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000))
+ return (EINVAL);
+
/* Reset the interrupted flag: */
curthread->interrupted = 0;
+ curthread->timeout = 0;
+ curthread->wakeup_time.tv_sec = -1;
/*
* Enter a loop waiting to become the mutex owner. We need a
@@ -501,6 +511,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
} else {
+ /* Set the wakeup time: */
+ if (abstime) {
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ }
+
/*
* Join the queue of threads waiting to lock
* the mutex and save a pointer to the mutex.
@@ -521,6 +539,13 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Schedule the next thread: */
_thr_sched_switch(curthread);
+
+ if (THR_IN_MUTEXQ(curthread)) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ mutex_queue_remove(*m, curthread);
+ curthread->data.mutex = NULL;
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
}
break;
@@ -560,6 +585,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
} else {
+ /* Set the wakeup time: */
+ if (abstime) {
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ }
+
/*
* Join the queue of threads waiting to lock
* the mutex and save a pointer to the mutex.
@@ -585,6 +618,13 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Schedule the next thread: */
_thr_sched_switch(curthread);
+
+ if (THR_IN_MUTEXQ(curthread)) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ mutex_queue_remove(*m, curthread);
+ curthread->data.mutex = NULL;
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
}
break;
@@ -634,6 +674,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Unlock the mutex structure: */
THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
} else {
+ /* Set the wakeup time: */
+ if (abstime) {
+ curthread->wakeup_time.tv_sec =
+ abstime->tv_sec;
+ curthread->wakeup_time.tv_nsec =
+ abstime->tv_nsec;
+ }
+
/*
* Join the queue of threads waiting to lock
* the mutex and save a pointer to the mutex.
@@ -659,6 +707,14 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
/* Schedule the next thread: */
_thr_sched_switch(curthread);
+
+ if (THR_IN_MUTEXQ(curthread)) {
+ THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
+ mutex_queue_remove(*m, curthread);
+ curthread->data.mutex = NULL;
+ THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
+ }
+
/*
* The threads priority may have changed while
* waiting for the mutex causing a ceiling
@@ -680,7 +736,10 @@ mutex_lock_common(struct pthread *curthread, pthread_mutex_t *m)
}
} while (((*m)->m_owner != curthread) && (ret == 0) &&
- (curthread->interrupted == 0));
+ (curthread->interrupted == 0) && (curthread->timeout == 0));
+
+ if (ret == 0 && curthread->timeout)
+ ret = ETIMEDOUT;
/*
* Check to see if this thread was interrupted and
@@ -720,7 +779,7 @@ __pthread_mutex_lock(pthread_mutex_t *m)
* initialization:
*/
else if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0))
- ret = mutex_lock_common(curthread, m);
+ ret = mutex_lock_common(curthread, m, NULL);
return (ret);
}
@@ -746,7 +805,56 @@ _pthread_mutex_lock(pthread_mutex_t *m)
*/
else if ((*m != NULL) ||
((ret = init_static_private(curthread, m)) == 0))
- ret = mutex_lock_common(curthread, m);
+ ret = mutex_lock_common(curthread, m, NULL);
+
+ return (ret);
+}
+
+int
+__pthread_mutex_timedlock(pthread_mutex_t *m,
+ const struct timespec *abs_timeout)
+{
+ struct pthread *curthread;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+
+ curthread = _get_curthread();
+ if (m == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization:
+ */
+ else if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0))
+ ret = mutex_lock_common(curthread, m, abs_timeout);
+
+ return (ret);
+}
+
+int
+_pthread_mutex_timedlock(pthread_mutex_t *m,
+ const struct timespec *abs_timeout)
+{
+ struct pthread *curthread;
+ int ret = 0;
+
+ if (_thr_initial == NULL)
+ _libpthread_init(NULL);
+ curthread = _get_curthread();
+
+ if (m == NULL)
+ ret = EINVAL;
+
+ /*
+ * If the mutex is statically initialized, perform the dynamic
+ * initialization marking it private (delete safe):
+ */
+ else if ((*m != NULL) ||
+ ((ret = init_static_private(curthread, m)) == 0))
+ ret = mutex_lock_common(curthread, m, abs_timeout);
return (ret);
}
diff --git a/lib/libpthread/thread/thr_private.h b/lib/libpthread/thread/thr_private.h
index 6302299..2127619 100644
--- a/lib/libpthread/thread/thr_private.h
+++ b/lib/libpthread/thread/thr_private.h
@@ -390,6 +390,18 @@ struct pthread_cond_attr {
long c_flags;
};
+struct pthread_barrier {
+ pthread_mutex_t b_lock;
+ pthread_cond_t b_cond;
+ int b_count;
+ int b_waiters;
+ int b_generation;
+};
+
+struct pthread_barrierattr {
+ int pshared;
+};
+
/*
* Flags for condition variables.
*/
OpenPOWER on IntegriCloud