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 . + * Copyright (c) 2006 David Xu . * 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; + struct pthread_mutex *m; + int ret; - THR_ASSERT((mutex != NULL) && (*mutex != NULL), - "Uninitialized mutex in mutex_trylock_common"); + 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 {} */ - /* 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; - } - - /* Unlock the mutex structure: */ - THR_LOCK_RELEASE(curthread, &(*mutex)->m_lock); - - /* 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); - 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); + 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 { - 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); - } + 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); } - 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; + struct pthread_mutex *m; 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; - - /* 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 (__predict_false((m = *mutex) == NULL)) + return (EINVAL); /* - * 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. + * Check if the running thread is not the owner of the mutex. */ - 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; - - /* - * Start walking the mutexes the thread has taken since - * taking this 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. + * Clear the count in case this is a recursive mutex. */ - 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... - */ - 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); + _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) +int +_pthread_mutex_getprioceiling(pthread_mutex_t *mutex, + int *prioceiling) { - struct pthread *pthread; - long tid = -1; + int ret; - /* 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); + if (*mutex == NULL) + ret = EINVAL; + else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else + ret = (*mutex)->m_prio; - /* 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); - } - - if ((pthread == NULL) && (mutex->m_protocol == PTHREAD_PRIO_INHERIT)) - /* This mutex has no priority: */ - mutex->m_prio = 0; - return (tid); + return(ret); } -#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_setprioceiling(pthread_mutex_t *mutex, + int prioceiling, int *old_ceiling) { - pthread_t pthread; + int ret = 0; + int tmp; - 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 if ((ret = pthread_mutex_lock(mutex)) == 0) { + tmp = (*mutex)->m_prio; + (*mutex)->m_prio = prioceiling; + ret = pthread_mutex_unlock(mutex); + + /* Return the old ceiling. */ + *old_ceiling = tmp; } - - return (pthread); -} -#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) -{ - if ((pthread->sflags & THR_FLAGS_IN_SYNCQ) != 0) { - TAILQ_REMOVE(&mutex->m_queue, pthread, sqe); - pthread->sflags &= ~THR_FLAGS_IN_SYNCQ; - } -} - -/* - * 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); - - 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); - } - 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); }