aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libthr/thread/Makefile.inc2
-rw-r--r--lib/libthr/thread/thr_create.c1
-rw-r--r--lib/libthr/thread/thr_init.c3
-rw-r--r--lib/libthr/thread/thr_mutex.c1240
-rw-r--r--lib/libthr/thread/thr_mutexattr.c63
-rw-r--r--lib/libthr/thread/thr_private.h40
-rw-r--r--lib/libthr/thread/thr_setschedparam.c50
7 files changed, 200 insertions, 1199 deletions
diff --git a/lib/libthr/thread/Makefile.inc b/lib/libthr/thread/Makefile.inc
index 33ca99e5e3d3..51d5ad736e94 100644
--- a/lib/libthr/thread/Makefile.inc
+++ b/lib/libthr/thread/Makefile.inc
@@ -30,8 +30,6 @@ SRCS+= \
thr_multi_np.c \
thr_mutex.c \
thr_mutexattr.c \
- thr_mutex_prioceiling.c \
- thr_mutex_protocol.c \
thr_once.c \
thr_printf.c \
thr_pspinlock.c \
diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c
index 6b67f4ea9301..b35f6b73e55b 100644
--- a/lib/libthr/thread/thr_create.c
+++ b/lib/libthr/thread/thr_create.c
@@ -129,7 +129,6 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
/* Initialize the mutex queue: */
TAILQ_INIT(&new_thread->mutexq);
- TAILQ_INIT(&new_thread->pri_mutexq);
/* Initialise hooks in the thread structure: */
if (new_thread->attr.suspend == THR_CREATE_SUSPENDED) {
diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c
index 2ddacc924459..725ea4e78692 100644
--- a/lib/libthr/thread/thr_init.c
+++ b/lib/libthr/thread/thr_init.c
@@ -68,7 +68,7 @@ atfork_head _thr_atfork_list = TAILQ_HEAD_INITIALIZER(_thr_atfork_list);
umtx_t _thr_atfork_lock;
struct pthread_attr _pthread_attr_default = {
- .sched_policy = SCHED_RR,
+ .sched_policy = SCHED_OTHER,
.sched_inherit = 0,
.sched_interval = TIMESLICE_USEC,
.prio = THR_DEFAULT_PRIORITY,
@@ -424,7 +424,6 @@ init_main_thread(struct pthread *thread)
/* Initialize the mutex queue: */
TAILQ_INIT(&thread->mutexq);
- TAILQ_INIT(&thread->pri_mutexq);
thread->state = PS_RUNNING;
diff --git a/lib/libthr/thread/thr_mutex.c b/lib/libthr/thread/thr_mutex.c
index 2b5eeef54d43..67b4760796a7 100644
--- a/lib/libthr/thread/thr_mutex.c
+++ b/lib/libthr/thread/thr_mutex.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
+ * Copyright (c) 2006 David Xu <davidxu@freebsd.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,39 +55,19 @@
((m)->m_qe.tqe_next != NULL)) \
PANIC("mutex is on list"); \
} while (0)
-#define THR_ASSERT_NOT_IN_SYNCQ(thr) do { \
- THR_ASSERT(((thr)->sflags & THR_FLAGS_IN_SYNCQ) == 0, \
- "thread in syncq when it shouldn't be."); \
-} while (0);
#else
#define MUTEX_INIT_LINK(m)
#define MUTEX_ASSERT_IS_OWNED(m)
#define MUTEX_ASSERT_NOT_OWNED(m)
-#define THR_ASSERT_NOT_IN_SYNCQ(thr)
#endif
-#define THR_IN_MUTEXQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
-#define MUTEX_DESTROY(m) do { \
- free(m); \
-} while (0)
-
-
/*
* Prototypes
*/
-static long mutex_handoff(struct pthread *, struct pthread_mutex *);
-static int mutex_self_trylock(struct pthread *, pthread_mutex_t);
-static int mutex_self_lock(struct pthread *, pthread_mutex_t,
+static int mutex_self_trylock(struct pthread *, pthread_mutex_t);
+static int mutex_self_lock(struct pthread *, pthread_mutex_t,
const struct timespec *abstime);
-static int mutex_unlock_common(pthread_mutex_t *, int);
-static void mutex_priority_adjust(struct pthread *, pthread_mutex_t);
-static void mutex_rescan_owned (struct pthread *, struct pthread *,
- struct pthread_mutex *);
-#if 0
-static pthread_t mutex_queue_deq(pthread_mutex_t);
-#endif
-static void mutex_queue_remove(pthread_mutex_t, pthread_t);
-static void mutex_queue_enq(pthread_mutex_t, pthread_t);
+static int mutex_unlock_common(pthread_mutex_t *, int);
__weak_reference(__pthread_mutex_init, pthread_mutex_init);
__weak_reference(__pthread_mutex_lock, pthread_mutex_lock);
@@ -98,21 +79,18 @@ __weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock);
__weak_reference(_pthread_mutex_destroy, pthread_mutex_destroy);
__weak_reference(_pthread_mutex_unlock, pthread_mutex_unlock);
+__weak_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling);
+__weak_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling);
+
static int
mutex_init(pthread_mutex_t *mutex,
const pthread_mutexattr_t *mutex_attr, int private)
{
- static const struct pthread_mutex_attr default_attr = {
- .m_type = PTHREAD_MUTEX_DEFAULT,
- .m_protocol = PTHREAD_PRIO_NONE,
- .m_ceiling = THR_MAX_PRIORITY,
- .m_flags = 0
- };
const struct pthread_mutex_attr *attr;
struct pthread_mutex *pmutex;
if (mutex_attr == NULL) {
- attr = &default_attr;
+ attr = &_pthread_mutexattr_default;
} else {
attr = *mutex_attr;
if (attr->m_type < PTHREAD_MUTEX_ERRORCHECK ||
@@ -223,16 +201,8 @@ _mutex_fork(struct pthread *curthread)
* process shared mutex is not supported, so I
* am not worried.
*/
- TAILQ_FOREACH(m, &curthread->mutexq, m_qe) {
+ TAILQ_FOREACH(m, &curthread->mutexq, m_qe)
m->m_lock = (umtx_t)curthread->tid;
- }
-
- /* Clear contender for priority mutexes */
- TAILQ_FOREACH(m, &curthread->pri_mutexq, m_qe) {
- /* clear another thread locked us */
- _thr_umtx_init(&m->m_lock);
- TAILQ_INIT(&m->m_queue);
- }
}
int
@@ -242,7 +212,7 @@ _pthread_mutex_destroy(pthread_mutex_t *mutex)
pthread_mutex_t m;
int ret = 0;
- if (mutex == NULL || *mutex == NULL)
+ if (__predict_false(*mutex == NULL))
ret = EINVAL;
else {
/*
@@ -266,148 +236,38 @@ _pthread_mutex_destroy(pthread_mutex_t *mutex)
} else {
/*
* Save a pointer to the mutex so it can be free'd
- * and set the caller's pointer to NULL:
+ * and set the caller's pointer to NULL.
*/
m = *mutex;
*mutex = NULL;
- /* Unlock the mutex structure: */
- _thr_umtx_unlock(&m->m_lock, curthread->tid);
+ THR_UMTX_UNLOCK(curthread, &m->m_lock);
- /*
- * Free the memory allocated for the mutex
- * structure:
- */
MUTEX_ASSERT_NOT_OWNED(m);
- MUTEX_DESTROY(m);
+ free(m);
}
}
- /* Return the completion status: */
return (ret);
}
static int
mutex_trylock_common(struct pthread *curthread, pthread_mutex_t *mutex)
{
- int ret = 0;
-
- THR_ASSERT((mutex != NULL) && (*mutex != NULL),
- "Uninitialized mutex in mutex_trylock_common");
-
- /* Short cut for simple mutex. */
- if ((*mutex)->m_protocol == PTHREAD_PRIO_NONE) {
- ret = THR_UMTX_TRYLOCK(curthread, &(*mutex)->m_lock);
- if (ret == 0) {
- (*mutex)->m_owner = curthread;
- /* Add to the list of owned mutexes: */
- MUTEX_ASSERT_NOT_OWNED(*mutex);
- TAILQ_INSERT_TAIL(&curthread->mutexq,
- (*mutex), m_qe);
- } else if ((*mutex)->m_owner == curthread) {
- ret = mutex_self_trylock(curthread, *mutex);
- } /* else {} */
-
- return (ret);
- }
-
- /* Code for priority mutex */
-
- /* Lock the mutex structure: */
- THR_LOCK_ACQUIRE(curthread, &(*mutex)->m_lock);
-
- /*
- * If the mutex was statically allocated, properly
- * initialize the tail queue.
- */
- if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) {
- TAILQ_INIT(&(*mutex)->m_queue);
- MUTEX_INIT_LINK(*mutex);
- (*mutex)->m_flags |= MUTEX_FLAGS_INITED;
- }
-
- /* Process according to mutex type: */
- switch ((*mutex)->m_protocol) {
- /* POSIX priority inheritence mutex: */
- case PTHREAD_PRIO_INHERIT:
- /* Check if this mutex is not locked: */
- if ((*mutex)->m_owner == NULL) {
- /* Lock the mutex for the running thread: */
- (*mutex)->m_owner = curthread;
-
- THR_LOCK(curthread);
- /* Track number of priority mutexes owned: */
- curthread->priority_mutex_count++;
-
- /*
- * The mutex takes on the attributes of the
- * running thread when there are no waiters.
- */
- (*mutex)->m_prio = curthread->active_priority;
- (*mutex)->m_saved_prio =
- curthread->inherited_priority;
- curthread->inherited_priority = (*mutex)->m_prio;
- THR_UNLOCK(curthread);
-
- /* Add to the list of owned mutexes: */
- MUTEX_ASSERT_NOT_OWNED(*mutex);
- TAILQ_INSERT_TAIL(&curthread->pri_mutexq,
- (*mutex), m_qe);
- } else if ((*mutex)->m_owner == curthread)
- ret = mutex_self_trylock(curthread, *mutex);
- else
- /* Return a busy error: */
- ret = EBUSY;
- break;
-
- /* POSIX priority protection mutex: */
- case PTHREAD_PRIO_PROTECT:
- /* Check for a priority ceiling violation: */
- if (curthread->active_priority > (*mutex)->m_prio)
- ret = EINVAL;
-
- /* Check if this mutex is not locked: */
- else if ((*mutex)->m_owner == NULL) {
- /* Lock the mutex for the running thread: */
- (*mutex)->m_owner = curthread;
-
- THR_LOCK(curthread);
- /* Track number of priority mutexes owned: */
- curthread->priority_mutex_count++;
-
- /*
- * The running thread inherits the ceiling
- * priority of the mutex and executes at that
- * priority.
- */
- curthread->active_priority = (*mutex)->m_prio;
- (*mutex)->m_saved_prio =
- curthread->inherited_priority;
- curthread->inherited_priority =
- (*mutex)->m_prio;
- THR_UNLOCK(curthread);
- /* Add to the list of owned mutexes: */
- MUTEX_ASSERT_NOT_OWNED(*mutex);
- TAILQ_INSERT_TAIL(&curthread->pri_mutexq,
- (*mutex), m_qe);
- } else if ((*mutex)->m_owner == curthread)
- ret = mutex_self_trylock(curthread, *mutex);
- else
- /* Return a busy error: */
- ret = EBUSY;
- break;
-
- /* Trap invalid mutex types: */
- default:
- /* Return an invalid argument error: */
- ret = EINVAL;
- break;
- }
+ struct pthread_mutex *m;
+ int ret;
- /* Unlock the mutex structure: */
- THR_LOCK_RELEASE(curthread, &(*mutex)->m_lock);
+ m = *mutex;
+ ret = THR_UMTX_TRYLOCK(curthread, &m->m_lock);
+ if (ret == 0) {
+ m->m_owner = curthread;
+ /* Add to the list of owned mutexes. */
+ MUTEX_ASSERT_NOT_OWNED(m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
+ } else if (m->m_owner == curthread) {
+ ret = mutex_self_trylock(curthread, m);
+ } /* else {} */
- /* Return the completion status: */
return (ret);
}
@@ -446,265 +306,44 @@ _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 *mutex,
const struct timespec * abstime)
{
struct timespec ts, ts2;
- long cycle;
+ struct pthread_mutex *m;
int ret = 0;
- THR_ASSERT((m != NULL) && (*m != NULL),
- "Uninitialized mutex in mutex_lock_common");
-
- if (abstime != NULL && (abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
- abstime->tv_nsec >= 1000000000))
- return (EINVAL);
-
- /* Short cut for simple mutex. */
-
- if ((*m)->m_protocol == PTHREAD_PRIO_NONE) {
- /* Default POSIX mutex: */
- ret = THR_UMTX_TRYLOCK(curthread, &(*m)->m_lock);
+ m = *mutex;
+ ret = THR_UMTX_TRYLOCK(curthread, &m->m_lock);
+ if (ret == 0) {
+ m->m_owner = curthread;
+ /* Add to the list of owned mutexes: */
+ MUTEX_ASSERT_NOT_OWNED(m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
+ } else if (m->m_owner == curthread) {
+ ret = mutex_self_lock(curthread, m, abstime);
+ } else {
+ if (abstime == NULL) {
+ THR_UMTX_LOCK(curthread, &m->m_lock);
+ ret = 0;
+ } else {
+ clock_gettime(CLOCK_REALTIME, &ts);
+ TIMESPEC_SUB(&ts2, abstime, &ts);
+ ret = THR_UMTX_TIMEDLOCK(curthread, &m->m_lock, &ts2);
+ /*
+ * Timed out wait is not restarted if
+ * it was interrupted, not worth to do it.
+ */
+ if (ret == EINTR)
+ ret = ETIMEDOUT;
+ }
if (ret == 0) {
- (*m)->m_owner = curthread;
+ m->m_owner = curthread;
/* Add to the list of owned mutexes: */
- MUTEX_ASSERT_NOT_OWNED(*m);
- TAILQ_INSERT_TAIL(&curthread->mutexq,
- (*m), m_qe);
- } else if ((*m)->m_owner == curthread) {
- ret = mutex_self_lock(curthread, *m, abstime);
- } else {
- if (abstime == NULL) {
- THR_UMTX_LOCK(curthread, &(*m)->m_lock);
- ret = 0;
- } else {
- clock_gettime(CLOCK_REALTIME, &ts);
- TIMESPEC_SUB(&ts2, abstime, &ts);
- ret = THR_UMTX_TIMEDLOCK(curthread,
- &(*m)->m_lock, &ts2);
- /*
- * Timed out wait is not restarted if
- * it was interrupted, not worth to do it.
- */
- if (ret == EINTR)
- ret = ETIMEDOUT;
- }
- if (ret == 0) {
- (*m)->m_owner = curthread;
- /* Add to the list of owned mutexes: */
- MUTEX_ASSERT_NOT_OWNED(*m);
- TAILQ_INSERT_TAIL(&curthread->mutexq,
- (*m), m_qe);
- }
+ MUTEX_ASSERT_NOT_OWNED(m);
+ TAILQ_INSERT_TAIL(&curthread->mutexq, m, m_qe);
}
- return (ret);
}
-
- /* Code for priority mutex */
-
- /*
- * Enter a loop waiting to become the mutex owner. We need a
- * loop in case the waiting thread is interrupted by a signal
- * to execute a signal handler. It is not (currently) possible
- * to remain in the waiting queue while running a handler.
- * Instead, the thread is interrupted and backed out of the
- * waiting queue prior to executing the signal handler.
- */
- do {
- /* Lock the mutex structure: */
- THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
-
- /*
- * If the mutex was statically allocated, properly
- * initialize the tail queue.
- */
- if (((*m)->m_flags & MUTEX_FLAGS_INITED) == 0) {
- TAILQ_INIT(&(*m)->m_queue);
- (*m)->m_flags |= MUTEX_FLAGS_INITED;
- MUTEX_INIT_LINK(*m);
- }
-
- /* Process according to mutex type: */
- switch ((*m)->m_protocol) {
- /* POSIX priority inheritence mutex: */
- case PTHREAD_PRIO_INHERIT:
- /* Check if this mutex is not locked: */
- if ((*m)->m_owner == NULL) {
- /* Lock the mutex for this thread: */
- (*m)->m_owner = curthread;
-
- THR_LOCK(curthread);
- /* Track number of priority mutexes owned: */
- curthread->priority_mutex_count++;
-
- /*
- * The mutex takes on attributes of the
- * running thread when there are no waiters.
- * Make sure the thread's scheduling lock is
- * held while priorities are adjusted.
- */
- (*m)->m_prio = curthread->active_priority;
- (*m)->m_saved_prio =
- curthread->inherited_priority;
- curthread->inherited_priority = (*m)->m_prio;
- THR_UNLOCK(curthread);
-
- /* Add to the list of owned mutexes: */
- MUTEX_ASSERT_NOT_OWNED(*m);
- TAILQ_INSERT_TAIL(&curthread->pri_mutexq,
- (*m), m_qe);
-
- /* Unlock the mutex structure: */
- THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
- } else if ((*m)->m_owner == curthread) {
- ret = mutex_self_lock(curthread, *m, abstime);
-
- /* Unlock the mutex structure: */
- THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
- } else {
- /*
- * Join the queue of threads waiting to lock
- * the mutex and save a pointer to the mutex.
- */
- mutex_queue_enq(*m, curthread);
- curthread->data.mutex = *m;
-
- if (curthread->active_priority > (*m)->m_prio)
- /* Adjust priorities: */
- mutex_priority_adjust(curthread, *m);
-
- THR_LOCK(curthread);
- cycle = curthread->cycle;
- THR_UNLOCK(curthread);
-
- /* Unlock the mutex structure: */
- THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
-
- clock_gettime(CLOCK_REALTIME, &ts);
- TIMESPEC_SUB(&ts2, abstime, &ts);
- ret = _thr_umtx_wait(&curthread->cycle, cycle,
- &ts2);
- if (ret == EINTR)
- ret = 0;
-
- if (THR_IN_MUTEXQ(curthread)) {
- THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
- mutex_queue_remove(*m, curthread);
- THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
- }
- /*
- * Only clear these after assuring the
- * thread is dequeued.
- */
- curthread->data.mutex = NULL;
- }
- break;
-
- /* POSIX priority protection mutex: */
- case PTHREAD_PRIO_PROTECT:
- /* Check for a priority ceiling violation: */
- if (curthread->active_priority > (*m)->m_prio) {
- /* Unlock the mutex structure: */
- THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
- ret = EINVAL;
- }
- /* Check if this mutex is not locked: */
- else if ((*m)->m_owner == NULL) {
- /*
- * Lock the mutex for the running
- * thread:
- */
- (*m)->m_owner = curthread;
-
- THR_LOCK(curthread);
- /* Track number of priority mutexes owned: */
- curthread->priority_mutex_count++;
-
- /*
- * The running thread inherits the ceiling
- * priority of the mutex and executes at that
- * priority. Make sure the thread's
- * scheduling lock is held while priorities
- * are adjusted.
- */
- curthread->active_priority = (*m)->m_prio;
- (*m)->m_saved_prio =
- curthread->inherited_priority;
- curthread->inherited_priority = (*m)->m_prio;
- THR_UNLOCK(curthread);
-
- /* Add to the list of owned mutexes: */
- MUTEX_ASSERT_NOT_OWNED(*m);
- TAILQ_INSERT_TAIL(&curthread->pri_mutexq,
- (*m), m_qe);
-
- /* Unlock the mutex structure: */
- THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
- } else if ((*m)->m_owner == curthread) {
- ret = mutex_self_lock(curthread, *m, abstime);
-
- /* Unlock the mutex structure: */
- THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
- } else {
- /*
- * Join the queue of threads waiting to lock
- * the mutex and save a pointer to the mutex.
- */
- mutex_queue_enq(*m, curthread);
- curthread->data.mutex = *m;
-
- /* Clear any previous error: */
- curthread->error = 0;
-
- THR_LOCK(curthread);
- cycle = curthread->cycle;
- THR_UNLOCK(curthread);
-
- /* Unlock the mutex structure: */
- THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
-
- clock_gettime(CLOCK_REALTIME, &ts);
- TIMESPEC_SUB(&ts2, abstime, &ts);
- ret = _thr_umtx_wait(&curthread->cycle, cycle,
- &ts2);
- if (ret == EINTR)
- ret = 0;
-
- curthread->data.mutex = NULL;
- if (THR_IN_MUTEXQ(curthread)) {
- THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
- mutex_queue_remove(*m, curthread);
- THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
- }
- /*
- * Only clear these after assuring the
- * thread is dequeued.
- */
- curthread->data.mutex = NULL;
-
- /*
- * The threads priority may have changed while
- * waiting for the mutex causing a ceiling
- * violation.
- */
- ret = curthread->error;
- curthread->error = 0;
- }
- break;
-
- /* Trap invalid mutex types: */
- default:
- /* Unlock the mutex structure: */
- THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
-
- /* Return an invalid argument error: */
- ret = EINVAL;
- break;
- }
-
- } while (((*m)->m_owner != curthread) && (ret == 0));
-
- /* Return the completion status: */
return (ret);
}
@@ -750,14 +389,17 @@ _pthread_mutex_lock(pthread_mutex_t *m)
}
int
-__pthread_mutex_timedlock(pthread_mutex_t *m,
- const struct timespec *abs_timeout)
+__pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *abstime)
{
struct pthread *curthread;
int ret = 0;
_thr_check_init();
+ if (abstime != NULL && (abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000))
+ return (EINVAL);
+
curthread = _get_curthread();
/*
@@ -765,20 +407,23 @@ __pthread_mutex_timedlock(pthread_mutex_t *m,
* initialization:
*/
if ((*m != NULL) || ((ret = init_static(curthread, m)) == 0))
- ret = mutex_lock_common(curthread, m, abs_timeout);
+ ret = mutex_lock_common(curthread, m, abstime);
return (ret);
}
int
-_pthread_mutex_timedlock(pthread_mutex_t *m,
- const struct timespec *abs_timeout)
+_pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *abstime)
{
- struct pthread *curthread;
+ struct pthread *curthread;
int ret = 0;
_thr_check_init();
+ if (abstime != NULL && (abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000))
+ return (EINVAL);
+
curthread = _get_curthread();
/*
@@ -787,7 +432,7 @@ _pthread_mutex_timedlock(pthread_mutex_t *m,
*/
if ((*m != NULL) ||
((ret = init_static_private(curthread, m)) == 0))
- ret = mutex_lock_common(curthread, m, abs_timeout);
+ ret = mutex_lock_common(curthread, m, abstime);
return (ret);
}
@@ -821,7 +466,6 @@ mutex_self_trylock(struct pthread *curthread, pthread_mutex_t m)
int ret;
switch (m->m_type) {
- /* case PTHREAD_MUTEX_DEFAULT: */
case PTHREAD_MUTEX_ERRORCHECK:
case PTHREAD_MUTEX_NORMAL:
ret = EBUSY;
@@ -848,11 +492,10 @@ static int
mutex_self_lock(struct pthread *curthread, pthread_mutex_t m,
const struct timespec *abstime)
{
- struct timespec ts1, ts2;
- int ret;
+ struct timespec ts1, ts2;
+ int ret;
switch (m->m_type) {
- /* case PTHREAD_MUTEX_DEFAULT: */
case PTHREAD_MUTEX_ERRORCHECK:
if (abstime) {
clock_gettime(CLOCK_REALTIME, &ts1);
@@ -874,10 +517,6 @@ mutex_self_lock(struct pthread *curthread, pthread_mutex_t m,
* deadlock on attempts to get a lock you already own.
*/
ret = 0;
- if (m->m_protocol != PTHREAD_PRIO_NONE) {
- /* Unlock the mutex structure: */
- THR_LOCK_RELEASE(curthread, &m->m_lock);
- }
if (abstime) {
clock_gettime(CLOCK_REALTIME, &ts1);
TIMESPEC_SUB(&ts2, abstime, &ts1);
@@ -909,529 +548,41 @@ mutex_self_lock(struct pthread *curthread, pthread_mutex_t m,
}
static int
-mutex_unlock_common(pthread_mutex_t *m, int add_reference)
+mutex_unlock_common(pthread_mutex_t *mutex, int add_reference)
{
struct pthread *curthread = _get_curthread();
- long tid = -1;
- int ret = 0;
-
- if (m == NULL || *m == NULL)
- ret = EINVAL;
- else {
- /* Short cut for simple mutex. */
-
- if ((*m)->m_protocol == PTHREAD_PRIO_NONE) {
- /*
- * Check if the running thread is not the owner of the
- * mutex:
- */
- if (__predict_false((*m)->m_owner != curthread)) {
- ret = EPERM;
- } else if (__predict_false(
- (*m)->m_type == PTHREAD_MUTEX_RECURSIVE &&
- (*m)->m_count > 0)) {
- /* Decrement the count: */
- (*m)->m_count--;
- if (add_reference)
- (*m)->m_refcount++;
- } else {
- /*
- * Clear the count in case this is a recursive
- * mutex.
- */
- (*m)->m_count = 0;
- (*m)->m_owner = NULL;
- /* Remove the mutex from the threads queue. */
- MUTEX_ASSERT_IS_OWNED(*m);
- TAILQ_REMOVE(&curthread->mutexq, (*m), m_qe);
- MUTEX_INIT_LINK(*m);
- if (add_reference)
- (*m)->m_refcount++;
- /*
- * Hand off the mutex to the next waiting
- * thread.
- */
- _thr_umtx_unlock(&(*m)->m_lock, curthread->tid);
- }
- return (ret);
- }
-
- /* Code for priority mutex */
-
- /* Lock the mutex structure: */
- THR_LOCK_ACQUIRE(curthread, &(*m)->m_lock);
-
- /* Process according to mutex type: */
- switch ((*m)->m_protocol) {
- /* POSIX priority inheritence mutex: */
- case PTHREAD_PRIO_INHERIT:
- /*
- * Check if the running thread is not the owner of the
- * mutex:
- */
- if ((*m)->m_owner != curthread)
- ret = EPERM;
- else if (((*m)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
- ((*m)->m_count > 0))
- /* Decrement the count: */
- (*m)->m_count--;
- else {
- /*
- * Clear the count in case this is recursive
- * mutex.
- */
- (*m)->m_count = 0;
-
- /*
- * Restore the threads inherited priority and
- * recompute the active priority (being careful
- * not to override changes in the threads base
- * priority subsequent to locking the mutex).
- */
- THR_LOCK(curthread);
- curthread->inherited_priority =
- (*m)->m_saved_prio;
- curthread->active_priority =
- MAX(curthread->inherited_priority,
- curthread->base_priority);
-
- /*
- * This thread now owns one less priority mutex.
- */
- curthread->priority_mutex_count--;
- THR_UNLOCK(curthread);
-
- /* Remove the mutex from the threads queue. */
- MUTEX_ASSERT_IS_OWNED(*m);
- TAILQ_REMOVE(&(*m)->m_owner->pri_mutexq,
- (*m), m_qe);
- MUTEX_INIT_LINK(*m);
-
- /*
- * Hand off the mutex to the next waiting
- * thread:
- */
- tid = mutex_handoff(curthread, *m);
- }
- break;
-
- /* POSIX priority ceiling mutex: */
- case PTHREAD_PRIO_PROTECT:
- /*
- * Check if the running thread is not the owner of the
- * mutex:
- */
- if ((*m)->m_owner != curthread)
- ret = EPERM;
- else if (((*m)->m_type == PTHREAD_MUTEX_RECURSIVE) &&
- ((*m)->m_count > 0))
- /* Decrement the count: */
- (*m)->m_count--;
- else {
- /*
- * Clear the count in case this is a recursive
- * mutex.
- */
- (*m)->m_count = 0;
-
- /*
- * Restore the threads inherited priority and
- * recompute the active priority (being careful
- * not to override changes in the threads base
- * priority subsequent to locking the mutex).
- */
- THR_LOCK(curthread);
- curthread->inherited_priority =
- (*m)->m_saved_prio;
- curthread->active_priority =
- MAX(curthread->inherited_priority,
- curthread->base_priority);
-
- /*
- * This thread now owns one less priority mutex.
- */
- curthread->priority_mutex_count--;
- THR_UNLOCK(curthread);
-
- /* Remove the mutex from the threads queue. */
- MUTEX_ASSERT_IS_OWNED(*m);
- TAILQ_REMOVE(&(*m)->m_owner->pri_mutexq,
- (*m), m_qe);
- MUTEX_INIT_LINK(*m);
-
- /*
- * Hand off the mutex to the next waiting
- * thread:
- */
- tid = mutex_handoff(curthread, *m);
- }
- break;
-
- /* Trap invalid mutex types: */
- default:
- /* Return an invalid argument error: */
- ret = EINVAL;
- break;
- }
-
- if ((ret == 0) && (add_reference != 0))
- /* Increment the reference count: */
- (*m)->m_refcount++;
-
- /* Unlock the mutex structure: */
- THR_LOCK_RELEASE(curthread, &(*m)->m_lock);
- }
-
- /* Return the completion status: */
- return (ret);
-}
-
-
-/*
- * This function is called when a change in base priority occurs for
- * a thread that is holding or waiting for a priority protection or
- * inheritence mutex. A change in a threads base priority can effect
- * changes to active priorities of other threads and to the ordering
- * of mutex locking by waiting threads.
- *
- * This must be called without the target thread's scheduling lock held.
- */
-void
-_mutex_notify_priochange(struct pthread *curthread, struct pthread *pthread,
- int propagate_prio)
-{
struct pthread_mutex *m;
+ int ret = 0;
- /* Adjust the priorites of any owned priority mutexes: */
- if (pthread->priority_mutex_count > 0) {
- /*
- * Rescan the mutexes owned by this thread and correct
- * their priorities to account for this threads change
- * in priority. This has the side effect of changing
- * the threads active priority.
- *
- * Be sure to lock the first mutex in the list of owned
- * mutexes. This acts as a barrier against another
- * simultaneous call to change the threads priority
- * and from the owning thread releasing the mutex.
- */
- m = TAILQ_FIRST(&pthread->pri_mutexq);
- if (m != NULL) {
- THR_LOCK_ACQUIRE(curthread, &m->m_lock);
- /*
- * Make sure the thread still owns the lock.
- */
- if (m == TAILQ_FIRST(&pthread->pri_mutexq))
- mutex_rescan_owned(curthread, pthread,
- /* rescan all owned */ NULL);
- THR_LOCK_RELEASE(curthread, &m->m_lock);
- }
- }
-
- /*
- * If this thread is waiting on a priority inheritence mutex,
- * check for priority adjustments. A change in priority can
- * also cause a ceiling violation(*) for a thread waiting on
- * a priority protection mutex; we don't perform the check here
- * as it is done in pthread_mutex_unlock.
- *
- * (*) It should be noted that a priority change to a thread
- * _after_ taking and owning a priority ceiling mutex
- * does not affect ownership of that mutex; the ceiling
- * priority is only checked before mutex ownership occurs.
- */
- if (propagate_prio != 0) {
- /*
- * Lock the thread's scheduling queue. This is a bit
- * convoluted; the "in synchronization queue flag" can
- * only be cleared with both the thread's scheduling and
- * mutex locks held. The thread's pointer to the wanted
- * mutex is guaranteed to be valid during this time.
- */
- THR_THREAD_LOCK(curthread, pthread);
-
- if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) == 0) ||
- ((m = pthread->data.mutex) == NULL))
- THR_THREAD_UNLOCK(curthread, pthread);
- else {
- /*
- * This thread is currently waiting on a mutex; unlock
- * the scheduling queue lock and lock the mutex. We
- * can't hold both at the same time because the locking
- * order could cause a deadlock.
- */
- THR_THREAD_UNLOCK(curthread, pthread);
- THR_LOCK_ACQUIRE(curthread, &m->m_lock);
-
- /*
- * Check to make sure this thread is still in the
- * same state (the lock above can yield the CPU to
- * another thread or the thread may be running on
- * another CPU).
- */
- if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) &&
- (pthread->data.mutex == m)) {
- /*
- * Remove and reinsert this thread into
- * the list of waiting threads to preserve
- * decreasing priority order.
- */
- mutex_queue_remove(m, pthread);
- mutex_queue_enq(m, pthread);
-
- if (m->m_protocol == PTHREAD_PRIO_INHERIT)
- /* Adjust priorities: */
- mutex_priority_adjust(curthread, m);
- }
-
- /* Unlock the mutex structure: */
- THR_LOCK_RELEASE(curthread, &m->m_lock);
- }
- }
-}
-
-/*
- * Called when a new thread is added to the mutex waiting queue or
- * when a threads priority changes that is already in the mutex
- * waiting queue.
- *
- * This must be called with the mutex locked by the current thread.
- */
-static void
-mutex_priority_adjust(struct pthread *curthread, pthread_mutex_t mutex)
-{
- pthread_mutex_t m = mutex;
- struct pthread *pthread_next, *pthread = mutex->m_owner;
- int done, temp_prio;
-
- /*
- * Calculate the mutex priority as the maximum of the highest
- * active priority of any waiting threads and the owning threads
- * active priority(*).
- *
- * (*) Because the owning threads current active priority may
- * reflect priority inherited from this mutex (and the mutex
- * priority may have changed) we must recalculate the active
- * priority based on the threads saved inherited priority
- * and its base priority.
- */
- pthread_next = TAILQ_FIRST(&m->m_queue); /* should never be NULL */
- temp_prio = MAX(pthread_next->active_priority,
- MAX(m->m_saved_prio, pthread->base_priority));
-
- /* See if this mutex really needs adjusting: */
- if (temp_prio == m->m_prio)
- /* No need to propagate the priority: */
- return;
-
- /* Set new priority of the mutex: */
- m->m_prio = temp_prio;
-
- /*
- * Don't unlock the mutex passed in as an argument. It is
- * expected to be locked and unlocked by the caller.
- */
- done = 1;
- do {
- /*
- * Save the threads priority before rescanning the
- * owned mutexes:
- */
- temp_prio = pthread->active_priority;
-
- /*
- * Fix the priorities for all mutexes held by the owning
- * thread since taking this mutex. This also has a
- * potential side-effect of changing the threads priority.
- *
- * At this point the mutex is locked by the current thread.
- * The owning thread can't release the mutex until it is
- * unlocked, so we should be able to safely walk its list
- * of owned mutexes.
- */
- mutex_rescan_owned(curthread, pthread, m);
-
- /*
- * If this isn't the first time through the loop,
- * the current mutex needs to be unlocked.
- */
- if (done == 0)
- THR_LOCK_RELEASE(curthread, &m->m_lock);
-
- /* Assume we're done unless told otherwise: */
- done = 1;
-
- /*
- * If the thread is currently waiting on a mutex, check
- * to see if the threads new priority has affected the
- * priority of the mutex.
- */
- if ((temp_prio != pthread->active_priority) &&
- ((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) &&
- ((m = pthread->data.mutex) != NULL) &&
- (m->m_protocol == PTHREAD_PRIO_INHERIT)) {
- /* Lock the mutex structure: */
- THR_LOCK_ACQUIRE(curthread, &m->m_lock);
-
- /*
- * Make sure the thread is still waiting on the
- * mutex:
- */
- if (((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) &&
- (m == pthread->data.mutex)) {
- /*
- * The priority for this thread has changed.
- * Remove and reinsert this thread into the
- * list of waiting threads to preserve
- * decreasing priority order.
- */
- mutex_queue_remove(m, pthread);
- mutex_queue_enq(m, pthread);
-
- /*
- * Grab the waiting thread with highest
- * priority:
- */
- pthread_next = TAILQ_FIRST(&m->m_queue);
-
- /*
- * Calculate the mutex priority as the maximum
- * of the highest active priority of any
- * waiting threads and the owning threads
- * active priority.
- */
- temp_prio = MAX(pthread_next->active_priority,
- MAX(m->m_saved_prio,
- m->m_owner->base_priority));
-
- if (temp_prio != m->m_prio) {
- /*
- * The priority needs to be propagated
- * to the mutex this thread is waiting
- * on and up to the owner of that mutex.
- */
- m->m_prio = temp_prio;
- pthread = m->m_owner;
-
- /* We're not done yet: */
- done = 0;
- }
- }
- /* Only release the mutex if we're done: */
- if (done != 0)
- THR_LOCK_RELEASE(curthread, &m->m_lock);
- }
- } while (done == 0);
-}
-
-static void
-mutex_rescan_owned(struct pthread *curthread, struct pthread *pthread,
- struct pthread_mutex *mutex)
-{
- struct pthread_mutex *m;
- struct pthread *pthread_next;
- int active_prio, inherited_prio;
+ if (__predict_false((m = *mutex) == NULL))
+ return (EINVAL);
/*
- * Start walking the mutexes the thread has taken since
- * taking this mutex.
+ * Check if the running thread is not the owner of the mutex.
*/
- if (mutex == NULL) {
- /*
- * A null mutex means start at the beginning of the owned
- * mutex list.
- */
- m = TAILQ_FIRST(&pthread->pri_mutexq);
-
- /* There is no inherited priority yet. */
- inherited_prio = 0;
+ if (__predict_false(m->m_owner != curthread)) {
+ ret = EPERM;
+ } else if (__predict_false(
+ m->m_type == PTHREAD_MUTEX_RECURSIVE &&
+ m->m_count > 0)) {
+ m->m_count--;
+ if (add_reference)
+ m->m_refcount++;
} else {
/*
- * The caller wants to start after a specific mutex. It
- * is assumed that this mutex is a priority inheritence
- * mutex and that its priority has been correctly
- * calculated.
- */
- m = TAILQ_NEXT(mutex, m_qe);
-
- /* Start inheriting priority from the specified mutex. */
- inherited_prio = mutex->m_prio;
- }
- active_prio = MAX(inherited_prio, pthread->base_priority);
-
- for (; m != NULL; m = TAILQ_NEXT(m, m_qe)) {
- /*
- * We only want to deal with priority inheritence
- * mutexes. This might be optimized by only placing
- * priority inheritence mutexes into the owned mutex
- * list, but it may prove to be useful having all
- * owned mutexes in this list. Consider a thread
- * exiting while holding mutexes...
+ * Clear the count in case this is a recursive mutex.
*/
- if (m->m_protocol == PTHREAD_PRIO_INHERIT) {
- /*
- * Fix the owners saved (inherited) priority to
- * reflect the priority of the previous mutex.
- */
- m->m_saved_prio = inherited_prio;
-
- if ((pthread_next = TAILQ_FIRST(&m->m_queue)) != NULL)
- /* Recalculate the priority of the mutex: */
- m->m_prio = MAX(active_prio,
- pthread_next->active_priority);
- else
- m->m_prio = active_prio;
-
- /* Recalculate new inherited and active priorities: */
- inherited_prio = m->m_prio;
- active_prio = MAX(m->m_prio, pthread->base_priority);
- }
- }
-
- /*
- * Fix the threads inherited priority and recalculate its
- * active priority.
- */
- pthread->inherited_priority = inherited_prio;
- active_prio = MAX(inherited_prio, pthread->base_priority);
-
- if (active_prio != pthread->active_priority) {
- /* Lock the thread's scheduling queue: */
- THR_THREAD_LOCK(curthread, pthread);
-
- /* if ((pthread->flags & THR_FLAGS_IN_RUNQ) == 0) */
- if (1) {
- /*
- * This thread is not in a run queue. Just set
- * its active priority.
- */
- pthread->active_priority = active_prio;
- }
- else {
- /*
- * This thread is in a run queue. Remove it from
- * the queue before changing its priority:
- */
- /* THR_RUNQ_REMOVE(pthread);*/
- /*
- * POSIX states that if the priority is being
- * lowered, the thread must be inserted at the
- * head of the queue for its priority if it owns
- * any priority protection or inheritence mutexes.
- */
- if ((active_prio < pthread->active_priority) &&
- (pthread->priority_mutex_count > 0)) {
- /* Set the new active priority. */
- pthread->active_priority = active_prio;
- /* THR_RUNQ_INSERT_HEAD(pthread); */
- } else {
- /* Set the new active priority. */
- pthread->active_priority = active_prio;
- /* THR_RUNQ_INSERT_TAIL(pthread);*/
- }
- }
- THR_THREAD_UNLOCK(curthread, pthread);
+ m->m_count = 0;
+ m->m_owner = NULL;
+ /* Remove the mutex from the threads queue. */
+ MUTEX_ASSERT_IS_OWNED(m);
+ TAILQ_REMOVE(&curthread->mutexq, m, m_qe);
+ MUTEX_INIT_LINK(m);
+ if (add_reference)
+ m->m_refcount++;
+ THR_UMTX_UNLOCK(curthread, &m->m_lock);
}
+ return (ret);
}
void
@@ -1439,194 +590,47 @@ _mutex_unlock_private(pthread_t pthread)
{
struct pthread_mutex *m, *m_next;
- for (m = TAILQ_FIRST(&pthread->pri_mutexq); m != NULL; m = m_next) {
+ for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) {
m_next = TAILQ_NEXT(m, m_qe);
if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0)
- pthread_mutex_unlock(&m);
- }
-}
-
-/*
- * Dequeue a waiting thread from the head of a mutex queue in descending
- * priority order.
- *
- * In order to properly dequeue a thread from the mutex queue and
- * make it runnable without the possibility of errant wakeups, it
- * is necessary to lock the thread's scheduling queue while also
- * holding the mutex lock.
- */
-static long
-mutex_handoff(struct pthread *curthread, struct pthread_mutex *mutex)
-{
- struct pthread *pthread;
- long tid = -1;
-
- /* Keep dequeueing until we find a valid thread: */
- mutex->m_owner = NULL;
- pthread = TAILQ_FIRST(&mutex->m_queue);
- while (pthread != NULL) {
- /* Take the thread's scheduling lock: */
- THR_THREAD_LOCK(curthread, pthread);
-
- /* Remove the thread from the mutex queue: */
- TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
- pthread->sflags &= ~THR_FLAGS_IN_SYNCQ;
-
- /*
- * Only exit the loop if the thread hasn't been
- * cancelled.
- */
- switch (mutex->m_protocol) {
- case PTHREAD_PRIO_NONE:
- /*
- * Assign the new owner and add the mutex to the
- * thread's list of owned mutexes.
- */
- mutex->m_owner = pthread;
- TAILQ_INSERT_TAIL(&pthread->pri_mutexq, mutex, m_qe);
- break;
-
- case PTHREAD_PRIO_INHERIT:
- /*
- * Assign the new owner and add the mutex to the
- * thread's list of owned mutexes.
- */
- mutex->m_owner = pthread;
- TAILQ_INSERT_TAIL(&pthread->pri_mutexq, mutex, m_qe);
-
- /* Track number of priority mutexes owned: */
- pthread->priority_mutex_count++;
-
- /*
- * Set the priority of the mutex. Since our waiting
- * threads are in descending priority order, the
- * priority of the mutex becomes the active priority
- * of the thread we just dequeued.
- */
- mutex->m_prio = pthread->active_priority;
-
- /* Save the owning threads inherited priority: */
- mutex->m_saved_prio = pthread->inherited_priority;
-
- /*
- * The owning threads inherited priority now becomes
- * his active priority (the priority of the mutex).
- */
- pthread->inherited_priority = mutex->m_prio;
- break;
-
- case PTHREAD_PRIO_PROTECT:
- if (pthread->active_priority > mutex->m_prio) {
- /*
- * Either the mutex ceiling priority has
- * been lowered and/or this threads priority
- * has been raised subsequent to the thread
- * being queued on the waiting list.
- */
- pthread->error = EINVAL;
- }
- else {
- /*
- * Assign the new owner and add the mutex
- * to the thread's list of owned mutexes.
- */
- mutex->m_owner = pthread;
- TAILQ_INSERT_TAIL(&pthread->pri_mutexq,
- mutex, m_qe);
-
- /* Track number of priority mutexes owned: */
- pthread->priority_mutex_count++;
-
- /*
- * Save the owning threads inherited
- * priority:
- */
- mutex->m_saved_prio =
- pthread->inherited_priority;
-
- /*
- * The owning thread inherits the ceiling
- * priority of the mutex and executes at
- * that priority:
- */
- pthread->inherited_priority = mutex->m_prio;
- pthread->active_priority = mutex->m_prio;
-
- }
- break;
- }
-
- /* Make the thread runnable and unlock the scheduling queue: */
- pthread->cycle++;
- _thr_umtx_wake(&pthread->cycle, 1);
-
- THR_THREAD_UNLOCK(curthread, pthread);
- if (mutex->m_owner == pthread)
- /* We're done; a valid owner was found. */
- break;
- else
- /* Get the next thread from the waiting queue: */
- pthread = TAILQ_NEXT(pthread, sqe);
+ _pthread_mutex_unlock(&m);
}
-
- if ((pthread == NULL) && (mutex->m_protocol == PTHREAD_PRIO_INHERIT))
- /* This mutex has no priority: */
- mutex->m_prio = 0;
- return (tid);
}
-#if 0
-/*
- * Dequeue a waiting thread from the head of a mutex queue in descending
- * priority order.
- */
-static pthread_t
-mutex_queue_deq(struct pthread_mutex *mutex)
+int
+_pthread_mutex_getprioceiling(pthread_mutex_t *mutex,
+ int *prioceiling)
{
- pthread_t pthread;
+ int ret;
- while ((pthread = TAILQ_FIRST(&mutex->m_queue)) != NULL) {
- TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
- pthread->sflags &= ~THR_FLAGS_IN_SYNCQ;
- }
+ if (*mutex == NULL)
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ ret = (*mutex)->m_prio;
- return (pthread);
+ return(ret);
}
-#endif
-/*
- * Remove a waiting thread from a mutex queue in descending priority order.
- */
-static void
-mutex_queue_remove(pthread_mutex_t mutex, pthread_t pthread)
+int
+_pthread_mutex_setprioceiling(pthread_mutex_t *mutex,
+ int prioceiling, int *old_ceiling)
{
- if ((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) {
- TAILQ_REMOVE(&mutex->m_queue, pthread, sqe);
- pthread->sflags &= ~THR_FLAGS_IN_SYNCQ;
- }
-}
+ int ret = 0;
+ int tmp;
-/*
- * Enqueue a waiting thread to a queue in descending priority order.
- */
-static void
-mutex_queue_enq(pthread_mutex_t mutex, pthread_t pthread)
-{
- pthread_t tid = TAILQ_LAST(&mutex->m_queue, mutex_head);
+ if (*mutex == NULL)
+ ret = EINVAL;
+ else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else if ((ret = pthread_mutex_lock(mutex)) == 0) {
+ tmp = (*mutex)->m_prio;
+ (*mutex)->m_prio = prioceiling;
+ ret = pthread_mutex_unlock(mutex);
- THR_ASSERT_NOT_IN_SYNCQ(pthread);
- /*
- * For the common case of all threads having equal priority,
- * we perform a quick check against the priority of the thread
- * at the tail of the queue.
- */
- if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
- TAILQ_INSERT_TAIL(&mutex->m_queue, pthread, sqe);
- else {
- tid = TAILQ_FIRST(&mutex->m_queue);
- while (pthread->active_priority <= tid->active_priority)
- tid = TAILQ_NEXT(tid, sqe);
- TAILQ_INSERT_BEFORE(tid, pthread, sqe);
+ /* Return the old ceiling. */
+ *old_ceiling = tmp;
}
- pthread->sflags |= THR_FLAGS_IN_SYNCQ;
+ return(ret);
}
diff --git a/lib/libthr/thread/thr_mutexattr.c b/lib/libthr/thread/thr_mutexattr.c
index ecfd1da40f17..e60ec67ce2de 100644
--- a/lib/libthr/thread/thr_mutexattr.c
+++ b/lib/libthr/thread/thr_mutexattr.c
@@ -79,6 +79,10 @@ __weak_reference(_pthread_mutexattr_settype, pthread_mutexattr_settype);
__weak_reference(_pthread_mutexattr_destroy, pthread_mutexattr_destroy);
__weak_reference(_pthread_mutexattr_getpshared, pthread_mutexattr_getpshared);
__weak_reference(_pthread_mutexattr_setpshared, pthread_mutexattr_setpshared);
+__weak_reference(_pthread_mutexattr_getprotocol, pthread_mutexattr_getprotocol);
+__weak_reference(_pthread_mutexattr_setprotocol, pthread_mutexattr_setprotocol);
+__weak_reference(_pthread_mutexattr_getprioceiling, pthread_mutexattr_getprioceiling);
+__weak_reference(_pthread_mutexattr_setprioceiling, pthread_mutexattr_setprioceiling);
int
_pthread_mutexattr_init(pthread_mutexattr_t *attr)
@@ -193,3 +197,62 @@ _pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
return (0);
}
+
+int
+_pthread_mutexattr_getprotocol(pthread_mutexattr_t *mattr, int *protocol)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else
+ *protocol = (*mattr)->m_protocol;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprotocol(pthread_mutexattr_t *mattr, int protocol)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL) ||
+ (protocol < PTHREAD_PRIO_NONE) || (protocol > PTHREAD_PRIO_PROTECT))
+ ret = EINVAL;
+ else {
+ (*mattr)->m_protocol = protocol;
+ (*mattr)->m_ceiling = THR_MAX_PRIORITY;
+ }
+ return(ret);
+}
+
+int
+_pthread_mutexattr_getprioceiling(pthread_mutexattr_t *mattr, int *prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ *prioceiling = (*mattr)->m_ceiling;
+
+ return(ret);
+}
+
+int
+_pthread_mutexattr_setprioceiling(pthread_mutexattr_t *mattr, int prioceiling)
+{
+ int ret = 0;
+
+ if ((mattr == NULL) || (*mattr == NULL))
+ ret = EINVAL;
+ else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT)
+ ret = EINVAL;
+ else
+ (*mattr)->m_ceiling = prioceiling;
+
+ return(ret);
+}
+
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index df41c9e134c0..c3f2c9f696b4 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -312,10 +312,6 @@ enum pthread_state {
PS_DEAD
};
-union pthread_wait_data {
- pthread_mutex_t mutex;
-};
-
struct pthread_specific_elem {
const void *data;
int seqno;
@@ -332,22 +328,15 @@ struct pthread_key {
* Thread structure.
*/
struct pthread {
- /*
- * Magic value to help recognize a valid thread structure
- * from an invalid one:
- */
-#define THR_MAGIC ((u_int32_t) 0xd09ba115)
- u_int32_t magic;
+ /* Kernel thread id. */
+ long tid;
+#define TID_TERMINATED 1
/*
* Lock for accesses to this thread structure.
*/
umtx_t lock;
- /* Kernel thread id. */
- long tid;
-#define TID_TERMINATED 1
-
/* Internal condition variable cycle number. */
umtx_t cycle;
@@ -424,12 +413,6 @@ struct pthread {
*/
TAILQ_ENTRY(pthread) sqe;
- /* Wait data. */
- union pthread_wait_data data;
-
- int sflags;
-#define THR_FLAGS_IN_SYNCQ 0x0001
-
/* Miscellaneous flags; only set with scheduling lock held. */
int flags;
#define THR_FLAGS_PRIVATE 0x0001
@@ -469,15 +452,9 @@ struct pthread {
*/
char active_priority;
- /* Number of priority ceiling or protection mutexes owned. */
- int priority_mutex_count;
-
/* Queue of currently owned simple type mutexes. */
TAILQ_HEAD(, pthread_mutex) mutexq;
- /* Queue of currently owned priority type mutexs. */
- TAILQ_HEAD(, pthread_mutex) pri_mutexq;
-
void *ret;
struct pthread_specific_elem *specific;
int specific_data_count;
@@ -495,6 +472,13 @@ struct pthread {
/* Cleanup handlers Link List */
struct pthread_cleanup *cleanup;
+ /*
+ * Magic value to help recognize a valid thread structure
+ * from an invalid one:
+ */
+#define THR_MAGIC ((u_int32_t) 0xd09ba115)
+ u_int32_t magic;
+
/* Enable event reporting */
int report_events;
@@ -602,8 +586,6 @@ do { \
#define GC_NEEDED() (_gc_count >= 5)
-#define THR_IN_SYNCQ(thrd) (((thrd)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
-
#define SHOULD_REPORT_EVENT(curthr, e) \
(curthr->report_events && \
(((curthr)->event_mask | _thread_event_mask ) & e) != 0)
@@ -664,7 +646,6 @@ __BEGIN_DECLS
int _thr_setthreaded(int) __hidden;
int _mutex_cv_lock(pthread_mutex_t *) __hidden;
int _mutex_cv_unlock(pthread_mutex_t *) __hidden;
-void _mutex_notify_priochange(struct pthread *, struct pthread *, int) __hidden;
int _mutex_reinit(pthread_mutex_t *) __hidden;
void _mutex_fork(struct pthread *curthread) __hidden;
void _mutex_unlock_private(struct pthread *) __hidden;
@@ -731,7 +712,6 @@ void _thr_unlink(struct pthread *, struct pthread *) __hidden;
void _thr_suspend_check(struct pthread *) __hidden;
void _thr_assert_lock_level(void) __hidden __dead2;
void _thr_ast(struct pthread *) __hidden;
-void _thr_timer_init(void) __hidden;
void _thr_once_init(void) __hidden;
void _thr_report_creation(struct pthread *curthread,
struct pthread *newthread) __hidden;
diff --git a/lib/libthr/thread/thr_setschedparam.c b/lib/libthr/thread/thr_setschedparam.c
index 4f0a60d3ef5e..100684951f09 100644
--- a/lib/libthr/thread/thr_setschedparam.c
+++ b/lib/libthr/thread/thr_setschedparam.c
@@ -40,25 +40,22 @@
__weak_reference(_pthread_setschedparam, pthread_setschedparam);
+/*
+ * Set a thread's scheduling parameters, this should be done
+ * in kernel, doing it in userland is no-op.
+ */
int
_pthread_setschedparam(pthread_t pthread, int policy,
const struct sched_param *param)
{
struct pthread *curthread = _get_curthread();
- int in_syncq;
- int in_readyq = 0;
- int old_prio;
int ret = 0;
if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) {
- /* Return an invalid argument error: */
ret = EINVAL;
} else if ((param->sched_priority < THR_MIN_PRIORITY) ||
(param->sched_priority > THR_MAX_PRIORITY)) {
- /* Return an unsupported value error. */
ret = ENOTSUP;
-
- /* Find the thread in the list of active threads: */
} else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
== 0) {
/*
@@ -71,7 +68,6 @@ _pthread_setschedparam(pthread_t pthread, int policy,
_thr_ref_delete(curthread, pthread);
return (ESRCH);
}
- in_syncq = pthread->sflags & THR_FLAGS_IN_SYNCQ;
/* Set the scheduling policy: */
pthread->attr.sched_policy = policy;
@@ -84,51 +80,13 @@ _pthread_setschedparam(pthread_t pthread, int policy,
*/
THR_THREAD_UNLOCK(curthread, pthread);
else {
- /*
- * Remove the thread from its current priority
- * queue before any adjustments are made to its
- * active priority:
- */
- old_prio = pthread->active_priority;
- /* if ((pthread->flags & THR_FLAGS_IN_RUNQ) != 0) */ {
- in_readyq = 1;
- /* THR_RUNQ_REMOVE(pthread); */
- }
-
- /* Set the thread base priority: */
- pthread->base_priority &=
- (THR_SIGNAL_PRIORITY | THR_RT_PRIORITY);
pthread->base_priority = param->sched_priority;
/* Recalculate the active priority: */
pthread->active_priority = MAX(pthread->base_priority,
pthread->inherited_priority);
- if (in_readyq) {
- if ((pthread->priority_mutex_count > 0) &&
- (old_prio > pthread->active_priority)) {
- /*
- * POSIX states that if the priority is
- * being lowered, the thread must be
- * inserted at the head of the queue for
- * its priority if it owns any priority
- * protection or inheritence mutexes.
- */
- /* THR_RUNQ_INSERT_HEAD(pthread); */
- }
- else
- /* THR_RUNQ_INSERT_TAIL(pthread)*/ ;
- }
-
- /* Unlock the threads scheduling queue: */
THR_THREAD_UNLOCK(curthread, pthread);
-
- /*
- * Check for any mutex priority adjustments. This
- * includes checking for a priority mutex on which
- * this thread is waiting.
- */
- _mutex_notify_priochange(curthread, pthread, in_syncq);
}
_thr_ref_delete(curthread, pthread);
}