PERFORCE change 67676 for review
David Xu
davidxu at FreeBSD.org
Sat Dec 25 05:12:26 PST 2004
http://perforce.freebsd.org/chv.cgi?CH=67676
Change 67676 by davidxu at davidxu_tiger on 2004/12/25 13:11:56
Use new umtx's condition variable feature to implement
pthread condition variable, we only need a few of lines
to implement it. The condition variable has already ablitity
to be shared among processes, but because current pthread_cond_t
is defined as a pointer, it can not be shared until pthread.h
is changed, that needs version bump.
Cancellation point does not work, will be added later.
Affected files ...
.. //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_cond.c#4 edit
Differences ...
==== //depot/projects/davidxu_thread/src/lib/libthread/thread/thr_cond.c#4 (text+ko) ====
@@ -35,22 +35,20 @@
#include <errno.h>
#include <string.h>
#include <pthread.h>
+#include <sys/limits.h>
+
#include "thr_private.h"
-#define THR_IN_CONDQ(thr) (((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
-#define THR_CONDQ_SET(thr) (thr)->sflags |= THR_FLAGS_IN_SYNCQ
-#define THR_CONDQ_CLEAR(thr) (thr)->sflags &= ~THR_FLAGS_IN_SYNCQ
-
/*
* Prototypes
*/
-static inline void cond_queue_remove(pthread_cond_t, pthread_t);
-static inline void cond_queue_enq(pthread_cond_t, pthread_t);
-static void cond_wait_backout(void *);
-static inline void check_continuation(struct pthread *,
- struct pthread_cond *, pthread_mutex_t *);
-static int init_static(struct pthread *thread,
- pthread_cond_t *cond);
+static inline void check_continuation(struct pthread *,
+ struct pthread_cond *, pthread_mutex_t *);
+static int init_static(struct pthread *thread,
+ pthread_cond_t *cond);
+static int cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec *abstime);
+static int cond_signal_common(pthread_cond_t *cond, int broadcast);
/*
* Double underscore versions are cancellation points. Single underscore
@@ -69,61 +67,24 @@
int
_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
{
- enum pthread_cond_type type;
pthread_cond_t pcond;
- int flags;
int rval = 0;
if (cond == NULL)
rval = EINVAL;
else {
- /*
- * Check if a pointer to a condition variable attribute
- * structure was passed by the caller:
- */
- if (cond_attr != NULL && *cond_attr != NULL) {
- /* Default to a fast condition variable: */
- type = (*cond_attr)->c_type;
- flags = (*cond_attr)->c_flags;
+ if ((pcond = (pthread_cond_t)
+ malloc(sizeof(struct pthread_cond))) == NULL) {
+ rval = ENOMEM;
} else {
- /* Default to a fast condition variable: */
- type = COND_TYPE_FAST;
- flags = 0;
- }
-
- /* Process according to condition variable type: */
- switch (type) {
- /* Fast condition variable: */
- case COND_TYPE_FAST:
- /* Nothing to do here. */
- break;
-
- /* Trap invalid condition variable types: */
- default:
- /* Return an invalid argument error: */
- rval = EINVAL;
- break;
+ /*
+ * Initialise the condition variable structure:
+ */
+ umtx_init(&pcond->c_lock);
+ pcond->c_count = 0;
+ pcond->c_flags = 0;
+ *cond = pcond;
}
-
- /* Check for no errors: */
- if (rval == 0) {
- if ((pcond = (pthread_cond_t)
- malloc(sizeof(struct pthread_cond))) == NULL) {
- rval = ENOMEM;
- } else {
- /*
- * Initialise the condition variable
- * structure:
- */
- _UMTX_INIT(&pcond->c_lock);
- TAILQ_INIT(&pcond->c_queue);
- pcond->c_flags = COND_FLAGS_INITED;
- pcond->c_type = type;
- pcond->c_mutex = NULL;
- pcond->c_seqno = 0;
- *cond = pcond;
- }
- }
}
/* Return the completion status: */
return (rval);
@@ -155,8 +116,15 @@
rval = EINVAL;
else {
/* Lock the condition variable structure: */
- THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
-
+ rval = UMTX_LOCK(&(*cond)->c_lock, curthread->tid);
+ if (rval)
+ return (rval);
+ while ((*cond)->c_count) {
+ rval = umtx_wake(&(*cond)->c_count, (*cond)->c_count);
+ if (rval <= 0)
+ break;
+ (*cond)->c_count -= rval;
+ }
/*
* NULL the caller's pointer now that the condition
* variable has been destroyed:
@@ -165,7 +133,7 @@
*cond = NULL;
/* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &cv->c_lock);
+ umtx_unlock(&cv->c_lock, curthread->tid);
/* Free the cond lock structure: */
@@ -180,186 +148,56 @@
return (rval);
}
-int
-_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+static int
+cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ const struct timespec *abstime)
{
struct pthread *curthread = _get_curthread();
int rval = 0;
- int done = 0;
- int mutex_locked = 1;
- int seqno;
-
- if (cond == NULL)
- return (EINVAL);
/*
* If the condition variable is statically initialized,
* perform the dynamic initialization:
*/
- if (*cond == NULL &&
- (rval = init_static(curthread, cond)) != 0)
+ if (__predict_false(*cond == NULL &&
+ (rval = init_static(curthread, cond)) != 0))
return (rval);
- /*
- * Enter a loop waiting for a condition signal or broadcast
- * to wake up this thread. A loop is needed 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.
- */
-
- /* Lock the condition variable structure: */
- THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
- seqno = (*cond)->c_seqno;
- do {
- /*
- * If the condvar was statically allocated, properly
- * initialize the tail queue.
- */
- if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
- TAILQ_INIT(&(*cond)->c_queue);
- (*cond)->c_flags |= COND_FLAGS_INITED;
+ if ((rval = UMTX_LOCK(&(*cond)->c_lock, curthread->tid)) == 0) {
+ rval = _mutex_cv_unlock(mutex);
+ if (__predict_false(rval)) {
+ umtx_unlock(&(*cond)->c_lock, curthread->tid);
+ return (rval);
}
- /* Process according to condition variable type: */
- switch ((*cond)->c_type) {
- /* Fast condition variable: */
- case COND_TYPE_FAST:
- if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
- ((*cond)->c_mutex != *mutex))) {
- /* Return invalid argument error: */
- rval = EINVAL;
- } else {
- /* Reset the timeout and interrupted flags: */
- curthread->timeout = 0;
- curthread->interrupted = 0;
+ /* I don't think you may have INIT_MAX threads. */
+ if ((*cond)->c_count != INT_MAX)
+ (*cond)->c_count++;
- /*
- * Queue the running thread for the condition
- * variable:
- */
- cond_queue_enq(*cond, curthread);
+ rval = umtx_timedwait(&(*cond)->c_lock, curthread->tid,
+ &(*cond)->c_count, abstime);
+ if (rval == EINTR)
+ rval = 0;
+ else if (rval == EAGAIN) /* POSIX needs ETIMEDOUT */
+ rval = ETIMEDOUT;
- /* Remember the mutex: */
- (*cond)->c_mutex = *mutex;
- curthread->sigbackout = cond_wait_backout;
-
- /* Wait forever: */
- curthread->wakeup_time.tv_sec = -1;
-
- /* Unlock the mutex: */
- if (mutex_locked &&
- ((rval = _mutex_cv_unlock(mutex)) != 0)) {
- /*
- * Cannot unlock the mutex, so remove
- * the running thread from the condition
- * variable queue:
- */
- cond_queue_remove(*cond, curthread);
- curthread->sigbackout = NULL;
-
- /* Check for no more waiters: */
- if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
- (*cond)->c_mutex = NULL;
- }
- else {
- /*
- * Don't unlock the mutex the next
- * time through the loop (if the
- * thread has to be requeued after
- * handling a signal).
- */
- mutex_locked = 0;
-
- /*
- * This thread is active and is in a
- * critical region (holding the cv
- * lock); we should be able to safely
- * set the state.
- */
- THR_LOCK_SWITCH(curthread);
- THR_SET_STATE(curthread, PS_COND_WAIT);
-
- /* Remember the CV: */
- curthread->data.cond = *cond;
-
- /* Unlock the CV structure: */
- THR_LOCK_RELEASE(curthread,
- &(*cond)->c_lock);
-
- /* Schedule the next thread: */
- _thr_sched_switch_unlocked(curthread);
-
- /*
- * XXX - This really isn't a good check
- * since there can be more than one
- * thread waiting on the CV. Signals
- * sent to threads waiting on mutexes
- * or CVs should really be deferred
- * until the threads are no longer
- * waiting, but POSIX says that signals
- * should be sent "as soon as possible".
- */
- done = (seqno != (*cond)->c_seqno);
- if (done && !THR_IN_CONDQ(curthread)) {
- /*
- * The thread is dequeued, so
- * it is safe to clear this.
- */
- curthread->data.cond = NULL;
- curthread->sigbackout = NULL;
- check_continuation(curthread,
- NULL, mutex);
- return (_mutex_cv_lock(mutex));
- }
-
- /* Relock the CV structure: */
- THR_LOCK_ACQUIRE(curthread,
- &(*cond)->c_lock);
-
- /*
- * Clear these after taking the lock to
- * prevent a race condition where a
- * signal can arrive before dequeueing
- * the thread.
- */
- curthread->data.cond = NULL;
- curthread->sigbackout = NULL;
- done = (seqno != (*cond)->c_seqno);
-
- if (THR_IN_CONDQ(curthread)) {
- cond_queue_remove(*cond,
- curthread);
-
- /* Check for no more waiters: */
- if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
- (*cond)->c_mutex = NULL;
- }
- }
- }
- break;
-
- /* Trap invalid condition variable types: */
- default:
- /* Return an invalid argument error: */
- rval = EINVAL;
- break;
- }
-
- check_continuation(curthread, *cond,
- mutex_locked ? NULL : mutex);
- } while ((done == 0) && (rval == 0));
-
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
-
- if (mutex_locked == 0)
+ /*
+ * Note! we don't touch condition variable after resuming!
+ * this makes it possible that waker can destroy the condition
+ * variable after calling pthread_cond_broadcast(), please
+ * see Single UNIX Specification Version 3 of
+ * pthread_cond_destroy().
+ */
+ check_continuation(curthread, NULL, mutex);
_mutex_cv_lock(mutex);
+ }
+ return (rval);
+}
- /* Return the completion status: */
- return (rval);
+int
+_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ return cond_wait_common(cond, mutex, NULL);
}
__strong_reference(_pthread_cond_wait, _thr_cond_wait);
@@ -371,7 +209,7 @@
int ret;
_thr_cancel_enter(curthread);
- ret = _pthread_cond_wait(cond, mutex);
+ ret = cond_wait_common(cond, mutex, NULL);
_thr_cancel_leave(curthread, 1);
return (ret);
}
@@ -380,192 +218,9 @@
_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
const struct timespec * abstime)
{
- struct pthread *curthread = _get_curthread();
- int rval = 0;
- int done = 0;
- int mutex_locked = 1;
- int seqno;
-
- THR_ASSERT(curthread->locklevel == 0,
- "cv_timedwait: locklevel is not zero!");
-
- if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
- abstime->tv_nsec >= 1000000000)
+ if (abstime == NULL)
return (EINVAL);
- /*
- * If the condition variable is statically initialized, perform dynamic
- * initialization.
- */
- if (*cond == NULL && (rval = init_static(curthread, cond)) != 0)
- return (rval);
-
- /*
- * Enter a loop waiting for a condition signal or broadcast
- * to wake up this thread. A loop is needed 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.
- */
-
- /* Lock the condition variable structure: */
- THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
- seqno = (*cond)->c_seqno;
- do {
- /*
- * If the condvar was statically allocated, properly
- * initialize the tail queue.
- */
- if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
- TAILQ_INIT(&(*cond)->c_queue);
- (*cond)->c_flags |= COND_FLAGS_INITED;
- }
-
- /* Process according to condition variable type: */
- switch ((*cond)->c_type) {
- /* Fast condition variable: */
- case COND_TYPE_FAST:
- if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
- ((*cond)->c_mutex != *mutex))) {
- /* Return invalid argument error: */
- rval = EINVAL;
- } else {
- /* Set the wakeup time: */
- curthread->wakeup_time.tv_sec = abstime->tv_sec;
- curthread->wakeup_time.tv_nsec =
- abstime->tv_nsec;
-
- /* Reset the timeout and interrupted flags: */
- curthread->timeout = 0;
- curthread->interrupted = 0;
-
- /*
- * Queue the running thread for the condition
- * variable:
- */
- cond_queue_enq(*cond, curthread);
-
- /* Remember the mutex and sequence number: */
- (*cond)->c_mutex = *mutex;
- curthread->sigbackout = cond_wait_backout;
-
- /* Unlock the mutex: */
- if (mutex_locked &&
- ((rval = _mutex_cv_unlock(mutex)) != 0)) {
- /*
- * Cannot unlock the mutex; remove the
- * running thread from the condition
- * variable queue:
- */
- cond_queue_remove(*cond, curthread);
- curthread->sigbackout = NULL;
-
- /* Check for no more waiters: */
- if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
- (*cond)->c_mutex = NULL;
- } else {
- /*
- * Don't unlock the mutex the next
- * time through the loop (if the
- * thread has to be requeued after
- * handling a signal).
- */
- mutex_locked = 0;
-
- /*
- * This thread is active and is in a
- * critical region (holding the cv
- * lock); we should be able to safely
- * set the state.
- */
- THR_LOCK_SWITCH(curthread);
- THR_SET_STATE(curthread, PS_COND_WAIT);
-
- /* Remember the CV: */
- curthread->data.cond = *cond;
-
- /* Unlock the CV structure: */
- THR_LOCK_RELEASE(curthread,
- &(*cond)->c_lock);
-
- /* Schedule the next thread: */
- _thr_sched_switch_unlocked(curthread);
-
- /*
- * XXX - This really isn't a good check
- * since there can be more than one
- * thread waiting on the CV. Signals
- * sent to threads waiting on mutexes
- * or CVs should really be deferred
- * until the threads are no longer
- * waiting, but POSIX says that signals
- * should be sent "as soon as possible".
- */
- done = (seqno != (*cond)->c_seqno);
- if (done && !THR_IN_CONDQ(curthread)) {
- /*
- * The thread is dequeued, so
- * it is safe to clear this.
- */
- curthread->data.cond = NULL;
- curthread->sigbackout = NULL;
- check_continuation(curthread,
- NULL, mutex);
- return (_mutex_cv_lock(mutex));
- }
-
- /* Relock the CV structure: */
- THR_LOCK_ACQUIRE(curthread,
- &(*cond)->c_lock);
-
- /*
- * Clear these after taking the lock to
- * prevent a race condition where a
- * signal can arrive before dequeueing
- * the thread.
- */
- curthread->data.cond = NULL;
- curthread->sigbackout = NULL;
-
- done = (seqno != (*cond)->c_seqno);
-
- if (THR_IN_CONDQ(curthread)) {
- cond_queue_remove(*cond,
- curthread);
-
- /* Check for no more waiters: */
- if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
- (*cond)->c_mutex = NULL;
- }
-
- if (curthread->timeout != 0) {
- /* The wait timedout. */
- rval = ETIMEDOUT;
- }
- }
- }
- break;
-
- /* Trap invalid condition variable types: */
- default:
- /* Return an invalid argument error: */
- rval = EINVAL;
- break;
- }
-
- check_continuation(curthread, *cond,
- mutex_locked ? NULL : mutex);
- } while ((done == 0) && (rval == 0));
-
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
-
- if (mutex_locked == 0)
- _mutex_cv_lock(mutex);
-
- /* Return the completion status: */
- return (rval);
+ return cond_wait_common(cond, mutex, abstime);
}
int
@@ -575,74 +230,59 @@
struct pthread *curthread = _get_curthread();
int ret;
+ if (abstime == NULL)
+ return (EINVAL);
_thr_cancel_enter(curthread);
ret = _pthread_cond_timedwait(cond, mutex, abstime);
_thr_cancel_leave(curthread, 1);
return (ret);
}
-
-int
-_pthread_cond_signal(pthread_cond_t * cond)
+static int
+cond_signal_common(pthread_cond_t *cond, int broadcast)
{
struct pthread *curthread = _get_curthread();
- struct pthread *pthread;
- long tid = -1;
int rval = 0;
- THR_ASSERT(curthread->locklevel == 0,
- "cv_timedwait: locklevel is not zero!");
- if (cond == NULL)
- rval = EINVAL;
- /*
- * If the condition variable is statically initialized, perform dynamic
- * initialization.
- */
- else if (*cond != NULL || (rval = init_static(curthread, cond)) == 0) {
- /* Lock the condition variable structure: */
- THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ if (__predict_false(*cond == NULL &&
+ (rval = init_static(curthread, cond)) != 0))
+ return (rval);
- /* Process according to condition variable type: */
- switch ((*cond)->c_type) {
- /* Fast condition variable: */
- case COND_TYPE_FAST:
- /* Increment the sequence number: */
- (*cond)->c_seqno++;
+ /* Lock the condition variable structure */
+ rval = UMTX_LOCK(&(*cond)->c_lock, curthread->tid);
+ if (__predict_false(rval))
+ return (rval);
- /*
- * Wakeups have to be done with the CV lock held;
- * otherwise there is a race condition where the
- * thread can timeout, run on another KSE, and enter
- * another blocking state (including blocking on a CV).
- */
- if ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
- != NULL) {
- THR_THREAD_LOCK(curthread, pthread);
- cond_queue_remove(*cond, pthread);
- pthread->sigbackout = NULL;
- tid = _thr_setrunnable_unlocked(pthread);
- THR_THREAD_UNLOCK(curthread, pthread);
- }
- /* Check for no more waiters: */
- if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
- (*cond)->c_mutex = NULL;
+ while ((*cond)->c_count) {
+ /* umtx_wake returns number of threads resumed */
+ rval = umtx_wake(&(*cond)->c_count,
+ broadcast ? (*cond)->c_count : 1);
+ if (rval > 0) {
+ /* some threads were resumed. */
+ (*cond)->c_count -= rval;
+ rval = 0;
+ } else if (rval == 0) {
+ (*cond)->c_count = 0;
break;
-
- /* Trap invalid condition variable types: */
- default:
- /* Return an invalid argument error: */
- rval = EINVAL;
+ } else {
+ rval = errno;
break;
}
-
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
- if (tid != -1)
- thr_wake(tid);
+ if (!broadcast)
+ break;
}
+ umtx_unlock(&(*cond)->c_lock, curthread->tid);
+ return (rval);
+}
- /* Return the completion status: */
- return (rval);
+int
+_pthread_cond_signal(pthread_cond_t * cond)
+{
+ return cond_signal_common(cond, 0);
}
__strong_reference(_pthread_cond_signal, _thr_cond_signal);
@@ -650,62 +290,7 @@
int
_pthread_cond_broadcast(pthread_cond_t * cond)
{
- struct pthread *curthread = _get_curthread();
- struct pthread *pthread;
- long tid = -1;
- int rval = 0;
-
- THR_ASSERT(curthread->locklevel == 0,
- "cv_timedwait: locklevel is not zero!");
- if (cond == NULL)
- rval = EINVAL;
- /*
- * If the condition variable is statically initialized, perform dynamic
- * initialization.
- */
- else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
- /* Lock the condition variable structure: */
- THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
-
- /* Process according to condition variable type: */
- switch ((*cond)->c_type) {
- /* Fast condition variable: */
- case COND_TYPE_FAST:
- /* Increment the sequence number: */
- (*cond)->c_seqno++;
-
- /*
- * Enter a loop to bring all threads off the
- * condition queue:
- */
- while ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
- != NULL) {
- THR_THREAD_LOCK(curthread, pthread);
- cond_queue_remove(*cond, pthread);
- pthread->sigbackout = NULL;
- tid = _thr_setrunnable_unlocked(pthread);
- THR_THREAD_UNLOCK(curthread, pthread);
- if (tid != -1)
- thr_wake(tid);
- }
-
- /* There are no more waiting threads: */
- (*cond)->c_mutex = NULL;
- break;
-
- /* Trap invalid condition variable types: */
- default:
- /* Return an invalid argument error: */
- rval = EINVAL;
- break;
- }
-
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
- }
-
- /* Return the completion status: */
- return (rval);
+ return cond_signal_common(cond, 1);
}
__strong_reference(_pthread_cond_broadcast, _thr_cond_broadcast);
@@ -714,101 +299,4 @@
check_continuation(struct pthread *curthread, struct pthread_cond *cond,
pthread_mutex_t *mutex)
{
- if ((curthread->interrupted != 0) &&
- (curthread->continuation != NULL)) {
- if (cond != NULL)
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &cond->c_lock);
- /*
- * Note that even though this thread may have been
- * canceled, POSIX requires that the mutex be
- * reaquired prior to cancellation.
- */
- if (mutex != NULL)
- _mutex_cv_lock(mutex);
- curthread->continuation((void *) curthread);
- PANIC("continuation returned in pthread_cond_wait.\n");
- }
-}
-
-static void
-cond_wait_backout(void *arg)
-{
- struct pthread *curthread = (struct pthread *)arg;
- pthread_cond_t cond;
-
- cond = curthread->data.cond;
- if (cond != NULL) {
- /* Lock the condition variable structure: */
- THR_LOCK_ACQUIRE(curthread, &cond->c_lock);
- curthread->data.cond = NULL;
-
- /* Process according to condition variable type: */
- switch (cond->c_type) {
- /* Fast condition variable: */
- case COND_TYPE_FAST:
- cond_queue_remove(cond, curthread);
-
- /* Check for no more waiters: */
- if (TAILQ_FIRST(&cond->c_queue) == NULL)
- cond->c_mutex = NULL;
- break;
-
- default:
- break;
- }
-
- /* Unlock the condition variable structure: */
- THR_LOCK_RELEASE(curthread, &cond->c_lock);
- }
- /* No need to call this again. */
- curthread->sigbackout = NULL;
-}
-
-/*
- * Remove a waiting thread from a condition queue in descending priority
- * order.
- */
-static inline void
-cond_queue_remove(pthread_cond_t cond, struct pthread *pthread)
-{
- /*
- * Because pthread_cond_timedwait() can timeout as well
- * as be signaled by another thread, it is necessary to
- * guard against removing the thread from the queue if
- * it isn't in the queue.
- */
- if (THR_IN_CONDQ(pthread)) {
- TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
- THR_CONDQ_CLEAR(pthread);
- }
-}
-
-/*
- * Enqueue a waiting thread to a condition queue in descending priority
- * order.
- */
-static inline void
-cond_queue_enq(pthread_cond_t cond, struct pthread *pthread)
-{
- struct pthread *tid = TAILQ_LAST(&cond->c_queue, cond_head);
-
- THR_ASSERT(!THR_IN_SYNCQ(pthread),
- "cond_queue_enq: thread already queued!");
-
- /*
- * 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(&cond->c_queue, pthread, sqe);
- else {
- tid = TAILQ_FIRST(&cond->c_queue);
- while (pthread->active_priority <= tid->active_priority)
- tid = TAILQ_NEXT(tid, sqe);
- TAILQ_INSERT_BEFORE(tid, pthread, sqe);
- }
- THR_CONDQ_SET(pthread);
- pthread->data.cond = cond;
}
More information about the p4-projects
mailing list