Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 25 Dec 2004 13:12:25 GMT
From:      David Xu <davidxu@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 67676 for review
Message-ID:  <200412251312.iBPDCP35037106@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=67676

Change 67676 by davidxu@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;
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200412251312.iBPDCP35037106>