thr_cond.c revision 58094
113546Sjulian/*
213546Sjulian * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
313546Sjulian * All rights reserved.
413546Sjulian *
513546Sjulian * Redistribution and use in source and binary forms, with or without
613546Sjulian * modification, are permitted provided that the following conditions
713546Sjulian * are met:
813546Sjulian * 1. Redistributions of source code must retain the above copyright
913546Sjulian *    notice, this list of conditions and the following disclaimer.
1013546Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1113546Sjulian *    notice, this list of conditions and the following disclaimer in the
1213546Sjulian *    documentation and/or other materials provided with the distribution.
1313546Sjulian * 3. All advertising materials mentioning features or use of this software
1413546Sjulian *    must display the following acknowledgement:
1513546Sjulian *	This product includes software developed by John Birrell.
1613546Sjulian * 4. Neither the name of the author nor the names of any co-contributors
1713546Sjulian *    may be used to endorse or promote products derived from this software
1813546Sjulian *    without specific prior written permission.
1913546Sjulian *
2013546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
2113546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2213546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2344963Sjb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2413546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2513546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2613546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2713546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2813546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2913546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3013546Sjulian * SUCH DAMAGE.
3113546Sjulian *
3250476Speter * $FreeBSD: head/lib/libkse/thread/thr_cond.c 58094 2000-03-15 13:59:27Z deischen $
3313546Sjulian */
3413546Sjulian#include <stdlib.h>
3513546Sjulian#include <errno.h>
3636830Sjb#include <string.h>
3713546Sjulian#ifdef _THREAD_SAFE
3813546Sjulian#include <pthread.h>
3913546Sjulian#include "pthread_private.h"
4013546Sjulian
4144963Sjb/*
4244963Sjb * Prototypes
4344963Sjb */
4444963Sjbstatic inline pthread_t	cond_queue_deq(pthread_cond_t);
4544963Sjbstatic inline void	cond_queue_remove(pthread_cond_t, pthread_t);
4644963Sjbstatic inline void	cond_queue_enq(pthread_cond_t, pthread_t);
4744963Sjb
4848046Sjb/* Reinitialize a condition variable to defaults. */
4948046Sjbint
5048046Sjb_cond_reinit(pthread_cond_t * cond)
5148046Sjb{
5248046Sjb	int ret = 0;
5344963Sjb
5448046Sjb	if (cond == NULL)
5548046Sjb		ret = EINVAL;
5648046Sjb	else if (*cond == NULL)
5748046Sjb		ret = pthread_cond_init(cond, NULL);
5848046Sjb	else {
5948046Sjb		/*
6048046Sjb		 * Initialize the condition variable structure:
6148046Sjb		 */
6248046Sjb		TAILQ_INIT(&(*cond)->c_queue);
6348046Sjb		(*cond)->c_flags = COND_FLAGS_INITED;
6448046Sjb		(*cond)->c_type = COND_TYPE_FAST;
6548046Sjb		(*cond)->c_mutex = NULL;
6648046Sjb		memset(&(*cond)->lock, 0, sizeof((*cond)->lock));
6748046Sjb	}
6848046Sjb	return (ret);
6948046Sjb}
7048046Sjb
7113546Sjulianint
7213546Sjulianpthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
7313546Sjulian{
7413546Sjulian	enum pthread_cond_type type;
7517706Sjulian	pthread_cond_t	pcond;
7613546Sjulian	int             rval = 0;
7713546Sjulian
7835509Sjb	if (cond == NULL)
7931402Salex		rval = EINVAL;
8035509Sjb	else {
8117706Sjulian		/*
8224827Sjb		 * Check if a pointer to a condition variable attribute
8324827Sjb		 * structure was passed by the caller:
8417706Sjulian		 */
8517706Sjulian		if (cond_attr != NULL && *cond_attr != NULL) {
8617706Sjulian			/* Default to a fast condition variable: */
8717706Sjulian			type = (*cond_attr)->c_type;
8817706Sjulian		} else {
8917706Sjulian			/* Default to a fast condition variable: */
9017706Sjulian			type = COND_TYPE_FAST;
9117706Sjulian		}
9213546Sjulian
9317706Sjulian		/* Process according to condition variable type: */
9417706Sjulian		switch (type) {
9524827Sjb		/* Fast condition variable: */
9617706Sjulian		case COND_TYPE_FAST:
9717706Sjulian			/* Nothing to do here. */
9817706Sjulian			break;
9913546Sjulian
10024827Sjb		/* Trap invalid condition variable types: */
10117706Sjulian		default:
10217706Sjulian			/* Return an invalid argument error: */
10331402Salex			rval = EINVAL;
10417706Sjulian			break;
10517706Sjulian		}
10613546Sjulian
10717706Sjulian		/* Check for no errors: */
10817706Sjulian		if (rval == 0) {
10924827Sjb			if ((pcond = (pthread_cond_t)
11024827Sjb			    malloc(sizeof(struct pthread_cond))) == NULL) {
11131402Salex				rval = ENOMEM;
11217706Sjulian			} else {
11317706Sjulian				/*
11417706Sjulian				 * Initialise the condition variable
11517706Sjulian				 * structure:
11617706Sjulian				 */
11744963Sjb				TAILQ_INIT(&pcond->c_queue);
11817706Sjulian				pcond->c_flags |= COND_FLAGS_INITED;
11917706Sjulian				pcond->c_type = type;
12044963Sjb				pcond->c_mutex = NULL;
12136830Sjb				memset(&pcond->lock,0,sizeof(pcond->lock));
12217706Sjulian				*cond = pcond;
12317706Sjulian			}
12417706Sjulian		}
12513546Sjulian	}
12613546Sjulian	/* Return the completion status: */
12713546Sjulian	return (rval);
12813546Sjulian}
12913546Sjulian
13013546Sjulianint
13113546Sjulianpthread_cond_destroy(pthread_cond_t * cond)
13213546Sjulian{
13313546Sjulian	int             rval = 0;
13413546Sjulian
13535509Sjb	if (cond == NULL || *cond == NULL)
13631402Salex		rval = EINVAL;
13735509Sjb	else {
13835509Sjb		/* Lock the condition variable structure: */
13936830Sjb		_SPINLOCK(&(*cond)->lock);
14013546Sjulian
14135509Sjb		/*
14235509Sjb		 * Free the memory allocated for the condition
14335509Sjb		 * variable structure:
14435509Sjb		 */
14535509Sjb		free(*cond);
14617706Sjulian
14735509Sjb		/*
14835509Sjb		 * NULL the caller's pointer now that the condition
14935509Sjb		 * variable has been destroyed:
15035509Sjb		 */
15135509Sjb		*cond = NULL;
15213546Sjulian	}
15313546Sjulian	/* Return the completion status: */
15413546Sjulian	return (rval);
15513546Sjulian}
15613546Sjulian
15713546Sjulianint
15813546Sjulianpthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
15913546Sjulian{
16056277Sjasone	int	rval = 0;
16156277Sjasone	int	interrupted = 0;
16213546Sjulian
16356698Sjasone	_thread_enter_cancellation_point();
16456698Sjasone
16535027Sjb	if (cond == NULL)
16631402Salex		rval = EINVAL;
16735027Sjb
16835027Sjb	/*
16935027Sjb	 * If the condition variable is statically initialized,
17035027Sjb	 * perform the dynamic initialization:
17135027Sjb	 */
17235027Sjb	else if (*cond != NULL ||
17335027Sjb	    (rval = pthread_cond_init(cond,NULL)) == 0) {
17453812Salfred
17553812Salfred		_thread_enter_cancellation_point();
17653812Salfred
17748046Sjb		/* Lock the condition variable structure: */
17848046Sjb		_SPINLOCK(&(*cond)->lock);
17948046Sjb
18047424Sjb		/*
18147424Sjb		 * If the condvar was statically allocated, properly
18247424Sjb		 * initialize the tail queue.
18347424Sjb		 */
18447424Sjb		if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
18547424Sjb			TAILQ_INIT(&(*cond)->c_queue);
18647424Sjb			(*cond)->c_flags |= COND_FLAGS_INITED;
18747424Sjb		}
18847424Sjb
18917706Sjulian		/* Process according to condition variable type: */
19017706Sjulian		switch ((*cond)->c_type) {
19124827Sjb		/* Fast condition variable: */
19217706Sjulian		case COND_TYPE_FAST:
19344963Sjb			if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
19444963Sjb			    ((*cond)->c_mutex != *mutex))) {
19544963Sjb				/* Unlock the condition variable structure: */
19644963Sjb				_SPINUNLOCK(&(*cond)->lock);
19740974Sdt
19844963Sjb				/* Return invalid argument error: */
19944963Sjb				rval = EINVAL;
20044963Sjb			} else {
20153812Salfred				/* Reset the timeout and interrupted flags: */
20244963Sjb				_thread_run->timeout = 0;
20353812Salfred				_thread_run->interrupted = 0;
20413546Sjulian
20540974Sdt				/*
20644963Sjb				 * Queue the running thread for the condition
20744963Sjb				 * variable:
20840974Sdt				 */
20944963Sjb				cond_queue_enq(*cond, _thread_run);
21013546Sjulian
21144963Sjb				/* Remember the mutex that is being used: */
21244963Sjb				(*cond)->c_mutex = *mutex;
21335509Sjb
21444963Sjb				/* Wait forever: */
21544963Sjb				_thread_run->wakeup_time.tv_sec = -1;
21644963Sjb
21744963Sjb				/* Unlock the mutex: */
21844963Sjb				if ((rval = _mutex_cv_unlock(mutex)) != 0) {
21944963Sjb					/*
22044963Sjb					 * Cannot unlock the mutex, so remove
22144963Sjb					 * the running thread from the condition
22244963Sjb					 * variable queue:
22344963Sjb					 */
22444963Sjb					cond_queue_remove(*cond, _thread_run);
22544963Sjb
22644963Sjb					/* Check for no more waiters: */
22744963Sjb					if (TAILQ_FIRST(&(*cond)->c_queue) ==
22844963Sjb					    NULL)
22944963Sjb						(*cond)->c_mutex = NULL;
23044963Sjb
23144963Sjb					/* Unlock the condition variable structure: */
23244963Sjb					_SPINUNLOCK(&(*cond)->lock);
23344963Sjb				}
23444963Sjb				else {
23544963Sjb					/*
23644963Sjb					 * Schedule the next thread and unlock
23744963Sjb					 * the condition variable structure:
23844963Sjb					 */
23944963Sjb					_thread_kern_sched_state_unlock(PS_COND_WAIT,
24044963Sjb				    	    &(*cond)->lock, __FILE__, __LINE__);
24144963Sjb
24253812Salfred					if (_thread_run->interrupted != 0) {
24353812Salfred						/*
24456277Sjasone						 * Remember that this thread
24556277Sjasone						 * was interrupted:
24656277Sjasone						 */
24756277Sjasone						interrupted = 1;
24856277Sjasone
24956277Sjasone						/*
25053812Salfred						 * Lock the condition variable
25153812Salfred						 * while removing the thread.
25253812Salfred						 */
25353812Salfred						_SPINLOCK(&(*cond)->lock);
25453812Salfred
25553812Salfred						cond_queue_remove(*cond,
25653812Salfred						    _thread_run);
25753812Salfred
25853812Salfred						/* Check for no more waiters: */
25953812Salfred						if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
26053812Salfred							(*cond)->c_mutex = NULL;
26153812Salfred
26253812Salfred						_SPINUNLOCK(&(*cond)->lock);
26353812Salfred					}
26453812Salfred
26553812Salfred					/*
26653812Salfred					 * Note that even though this thread may have
26753812Salfred					 * been canceled, POSIX requires that the mutex
26853812Salfred					 * be reaquired prior to cancellation.
26953812Salfred					 */
27044963Sjb					rval = _mutex_cv_lock(mutex);
27144963Sjb				}
27240974Sdt			}
27317706Sjulian			break;
27413546Sjulian
27524827Sjb		/* Trap invalid condition variable types: */
27617706Sjulian		default:
27740974Sdt			/* Unlock the condition variable structure: */
27840974Sdt			_SPINUNLOCK(&(*cond)->lock);
27940974Sdt
28017706Sjulian			/* Return an invalid argument error: */
28131402Salex			rval = EINVAL;
28217706Sjulian			break;
28317706Sjulian		}
28453812Salfred
28558094Sdeischen		if (interrupted != 0) {
28658094Sdeischen			if (_thread_run->continuation != NULL)
28758094Sdeischen				_thread_run->continuation((void *) _thread_run);
28858094Sdeischen			rval = EINTR;
28958094Sdeischen		}
29053812Salfred
29153812Salfred		_thread_leave_cancellation_point();
29213546Sjulian	}
29313546Sjulian
29456698Sjasone	_thread_leave_cancellation_point();
29556698Sjasone
29613546Sjulian	/* Return the completion status: */
29713546Sjulian	return (rval);
29813546Sjulian}
29913546Sjulian
30013546Sjulianint
30113546Sjulianpthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
30213546Sjulian		       const struct timespec * abstime)
30313546Sjulian{
30456277Sjasone	int	rval = 0;
30556277Sjasone	int	interrupted = 0;
30613546Sjulian
30756698Sjasone	_thread_enter_cancellation_point();
30856698Sjasone
30950601Sdeischen	if (cond == NULL || abstime == NULL)
31050601Sdeischen		rval = EINVAL;
31150601Sdeischen
31250065Salfred	if (abstime->tv_sec < 0 ||
31350601Sdeischen		abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000) {
31450601Sdeischen		errno = EINVAL;
31556698Sjasone		_thread_leave_cancellation_point();
31650601Sdeischen		return (-1);
31750601Sdeischen	}
31850065Salfred
31935027Sjb	/*
32035027Sjb	 * If the condition variable is statically initialized,
32135027Sjb	 * perform the dynamic initialization:
32235027Sjb	 */
32350601Sdeischen	if (*cond != NULL ||
32435027Sjb	    (rval = pthread_cond_init(cond,NULL)) == 0) {
32553812Salfred
32653812Salfred		_thread_enter_cancellation_point();
32753812Salfred
32848046Sjb		/* Lock the condition variable structure: */
32948046Sjb		_SPINLOCK(&(*cond)->lock);
33048046Sjb
33147424Sjb		/*
33247424Sjb		 * If the condvar was statically allocated, properly
33347424Sjb		 * initialize the tail queue.
33447424Sjb		 */
33547424Sjb		if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
33647424Sjb			TAILQ_INIT(&(*cond)->c_queue);
33747424Sjb			(*cond)->c_flags |= COND_FLAGS_INITED;
33847424Sjb		}
33947424Sjb
34017706Sjulian		/* Process according to condition variable type: */
34117706Sjulian		switch ((*cond)->c_type) {
34224827Sjb		/* Fast condition variable: */
34317706Sjulian		case COND_TYPE_FAST:
34444963Sjb			if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
34544963Sjb			    ((*cond)->c_mutex != *mutex))) {
34644963Sjb				/* Return invalid argument error: */
34744963Sjb				rval = EINVAL;
34813546Sjulian
34944963Sjb				/* Unlock the condition variable structure: */
35044963Sjb				_SPINUNLOCK(&(*cond)->lock);
35144963Sjb			} else {
35244963Sjb				/* Set the wakeup time: */
35344963Sjb				_thread_run->wakeup_time.tv_sec =
35444963Sjb				    abstime->tv_sec;
35544963Sjb				_thread_run->wakeup_time.tv_nsec =
35644963Sjb				    abstime->tv_nsec;
35713546Sjulian
35853812Salfred				/* Reset the timeout and interrupted flags: */
35944963Sjb				_thread_run->timeout = 0;
36053812Salfred				_thread_run->interrupted = 0;
36113546Sjulian
36217706Sjulian				/*
36344963Sjb				 * Queue the running thread for the condition
36444963Sjb				 * variable:
36517706Sjulian				 */
36644963Sjb				cond_queue_enq(*cond, _thread_run);
36740974Sdt
36844963Sjb				/* Remember the mutex that is being used: */
36944963Sjb				(*cond)->c_mutex = *mutex;
37013546Sjulian
37144963Sjb				/* Unlock the mutex: */
37244963Sjb				if ((rval = _mutex_cv_unlock(mutex)) != 0) {
37344963Sjb					/*
37444963Sjb					 * Cannot unlock the mutex, so remove
37544963Sjb					 * the running thread from the condition
37644963Sjb					 * variable queue:
37744963Sjb					 */
37844963Sjb					cond_queue_remove(*cond, _thread_run);
37944963Sjb
38044963Sjb					/* Check for no more waiters: */
38144963Sjb					if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
38244963Sjb						(*cond)->c_mutex = NULL;
38344963Sjb
38444963Sjb					/* Unlock the condition variable structure: */
38544963Sjb					_SPINUNLOCK(&(*cond)->lock);
38644963Sjb				} else {
38744963Sjb					/*
38844963Sjb					 * Schedule the next thread and unlock
38944963Sjb					 * the condition variable structure:
39044963Sjb					 */
39144963Sjb					_thread_kern_sched_state_unlock(PS_COND_WAIT,
39244963Sjb				  	     &(*cond)->lock, __FILE__, __LINE__);
39344963Sjb
39453812Salfred					/*
39553812Salfred					 * Check if the wait timedout or was
39653812Salfred					 * interrupted (canceled):
39753812Salfred					 */
39853812Salfred					if ((_thread_run->timeout == 0) &&
39953812Salfred					    (_thread_run->interrupted == 0)) {
40044963Sjb						/* Lock the mutex: */
40144963Sjb						rval = _mutex_cv_lock(mutex);
40253812Salfred
40353812Salfred					} else {
40456277Sjasone						/*
40556277Sjasone						 * Remember if this thread was
40656277Sjasone						 * interrupted:
40756277Sjasone						 */
40856277Sjasone						interrupted = _thread_run->interrupted;
40956277Sjasone
41044963Sjb						/* Lock the condition variable structure: */
41144963Sjb						_SPINLOCK(&(*cond)->lock);
41244963Sjb
41344963Sjb						/*
41444963Sjb						 * The wait timed out; remove
41544963Sjb						 * the thread from the condition
41644963Sjb					 	 * variable queue:
41744963Sjb						 */
41844963Sjb						cond_queue_remove(*cond,
41944963Sjb						    _thread_run);
42044963Sjb
42144963Sjb						/* Check for no more waiters: */
42244963Sjb						if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
42344963Sjb							(*cond)->c_mutex = NULL;
42444963Sjb
42544963Sjb						/* Unock the condition variable structure: */
42644963Sjb						_SPINUNLOCK(&(*cond)->lock);
42744963Sjb
42844963Sjb						/* Return a timeout error: */
42944963Sjb						rval = ETIMEDOUT;
43044963Sjb
43144963Sjb						/*
43253812Salfred						 * Lock the mutex and ignore any
43353812Salfred						 * errors.  Note that even though
43453812Salfred						 * this thread may have been
43553812Salfred						 * canceled, POSIX requires that
43653812Salfred						 * the mutex be reaquired prior
43753812Salfred						 * to cancellation.
43844963Sjb						 */
43944963Sjb						(void)_mutex_cv_lock(mutex);
44044963Sjb					}
44117706Sjulian				}
44213546Sjulian			}
44317706Sjulian			break;
44417706Sjulian
44524827Sjb		/* Trap invalid condition variable types: */
44617706Sjulian		default:
44740974Sdt			/* Unlock the condition variable structure: */
44840974Sdt			_SPINUNLOCK(&(*cond)->lock);
44940974Sdt
45017706Sjulian			/* Return an invalid argument error: */
45131402Salex			rval = EINVAL;
45217706Sjulian			break;
45313546Sjulian		}
45413546Sjulian
45558094Sdeischen		if (interrupted != 0) {
45658094Sdeischen			if (_thread_run->continuation != NULL)
45758094Sdeischen				_thread_run->continuation((void *) _thread_run);
45858094Sdeischen			rval = EINTR;
45958094Sdeischen		}
46053812Salfred
46153812Salfred		_thread_leave_cancellation_point();
46213546Sjulian	}
46313546Sjulian
46456698Sjasone	_thread_leave_cancellation_point();
46556698Sjasone
46613546Sjulian	/* Return the completion status: */
46713546Sjulian	return (rval);
46813546Sjulian}
46913546Sjulian
47013546Sjulianint
47113546Sjulianpthread_cond_signal(pthread_cond_t * cond)
47213546Sjulian{
47313546Sjulian	int             rval = 0;
47413546Sjulian	pthread_t       pthread;
47513546Sjulian
47635509Sjb	if (cond == NULL || *cond == NULL)
47731402Salex		rval = EINVAL;
47835509Sjb	else {
47948046Sjb		/*
48048046Sjb		 * Defer signals to protect the scheduling queues
48148046Sjb		 * from access by the signal handler:
48248046Sjb		 */
48348046Sjb		_thread_kern_sig_defer();
48448046Sjb
48535509Sjb		/* Lock the condition variable structure: */
48636830Sjb		_SPINLOCK(&(*cond)->lock);
48713546Sjulian
48817706Sjulian		/* Process according to condition variable type: */
48917706Sjulian		switch ((*cond)->c_type) {
49024827Sjb		/* Fast condition variable: */
49117706Sjulian		case COND_TYPE_FAST:
49253812Salfred			if ((pthread = cond_queue_deq(*cond)) != NULL)
49317706Sjulian				/* Allow the thread to run: */
49422315Sjulian				PTHREAD_NEW_STATE(pthread,PS_RUNNING);
49544963Sjb
49644963Sjb			/* Check for no more waiters: */
49744963Sjb			if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
49844963Sjb				(*cond)->c_mutex = NULL;
49917706Sjulian			break;
50017706Sjulian
50124827Sjb		/* Trap invalid condition variable types: */
50217706Sjulian		default:
50317706Sjulian			/* Return an invalid argument error: */
50431402Salex			rval = EINVAL;
50517706Sjulian			break;
50613546Sjulian		}
50713546Sjulian
50835509Sjb		/* Unlock the condition variable structure: */
50936830Sjb		_SPINUNLOCK(&(*cond)->lock);
51048046Sjb
51148046Sjb		/*
51248046Sjb		 * Undefer and handle pending signals, yielding if
51348046Sjb		 * necessary:
51448046Sjb		 */
51548046Sjb		_thread_kern_sig_undefer();
51613546Sjulian	}
51713546Sjulian
51813546Sjulian	/* Return the completion status: */
51913546Sjulian	return (rval);
52013546Sjulian}
52113546Sjulian
52213546Sjulianint
52313546Sjulianpthread_cond_broadcast(pthread_cond_t * cond)
52413546Sjulian{
52513546Sjulian	int             rval = 0;
52613546Sjulian	pthread_t       pthread;
52713546Sjulian
52835509Sjb	if (cond == NULL || *cond == NULL)
52935509Sjb		rval = EINVAL;
53035509Sjb	else {
53144963Sjb		/*
53248046Sjb		 * Defer signals to protect the scheduling queues
53348046Sjb		 * from access by the signal handler:
53444963Sjb		 */
53548046Sjb		_thread_kern_sig_defer();
53644963Sjb
53735509Sjb		/* Lock the condition variable structure: */
53836830Sjb		_SPINLOCK(&(*cond)->lock);
53913546Sjulian
54035509Sjb		/* Process according to condition variable type: */
54135509Sjb		switch ((*cond)->c_type) {
54235509Sjb		/* Fast condition variable: */
54335509Sjb		case COND_TYPE_FAST:
54435509Sjb			/*
54535509Sjb			 * Enter a loop to bring all threads off the
54635509Sjb			 * condition queue:
54735509Sjb			 */
54844963Sjb			while ((pthread = cond_queue_deq(*cond)) != NULL) {
54953812Salfred				PTHREAD_NEW_STATE(pthread,PS_RUNNING);
55035509Sjb			}
55144963Sjb
55244963Sjb			/* There are no more waiting threads: */
55344963Sjb			(*cond)->c_mutex = NULL;
55435509Sjb			break;
55535509Sjb
55635509Sjb		/* Trap invalid condition variable types: */
55735509Sjb		default:
55835509Sjb			/* Return an invalid argument error: */
55935509Sjb			rval = EINVAL;
56035509Sjb			break;
56113546Sjulian		}
56213546Sjulian
56335509Sjb		/* Unlock the condition variable structure: */
56436830Sjb		_SPINUNLOCK(&(*cond)->lock);
56544963Sjb
56648046Sjb		/*
56748046Sjb		 * Undefer and handle pending signals, yielding if
56848046Sjb		 * necessary:
56944963Sjb		 */
57048046Sjb		_thread_kern_sig_undefer();
57113546Sjulian	}
57213546Sjulian
57313546Sjulian	/* Return the completion status: */
57413546Sjulian	return (rval);
57513546Sjulian}
57644963Sjb
57744963Sjb/*
57844963Sjb * Dequeue a waiting thread from the head of a condition queue in
57944963Sjb * descending priority order.
58044963Sjb */
58144963Sjbstatic inline pthread_t
58244963Sjbcond_queue_deq(pthread_cond_t cond)
58344963Sjb{
58444963Sjb	pthread_t pthread;
58544963Sjb
58653812Salfred	while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
58744963Sjb		TAILQ_REMOVE(&cond->c_queue, pthread, qe);
58848046Sjb		pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
58953812Salfred		if ((pthread->timeout == 0) && (pthread->interrupted == 0))
59053812Salfred			/*
59153812Salfred			 * Only exit the loop when we find a thread
59253812Salfred			 * that hasn't timed out or been canceled;
59353812Salfred			 * those threads are already running and don't
59453812Salfred			 * need their run state changed.
59553812Salfred			 */
59653812Salfred			break;
59744963Sjb	}
59844963Sjb
59944963Sjb	return(pthread);
60044963Sjb}
60144963Sjb
60244963Sjb/*
60344963Sjb * Remove a waiting thread from a condition queue in descending priority
60444963Sjb * order.
60544963Sjb */
60644963Sjbstatic inline void
60744963Sjbcond_queue_remove(pthread_cond_t cond, pthread_t pthread)
60844963Sjb{
60944963Sjb	/*
61044963Sjb	 * Because pthread_cond_timedwait() can timeout as well
61144963Sjb	 * as be signaled by another thread, it is necessary to
61244963Sjb	 * guard against removing the thread from the queue if
61344963Sjb	 * it isn't in the queue.
61444963Sjb	 */
61548046Sjb	if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) {
61644963Sjb		TAILQ_REMOVE(&cond->c_queue, pthread, qe);
61748046Sjb		pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
61844963Sjb	}
61944963Sjb}
62044963Sjb
62144963Sjb/*
62244963Sjb * Enqueue a waiting thread to a condition queue in descending priority
62344963Sjb * order.
62444963Sjb */
62544963Sjbstatic inline void
62644963Sjbcond_queue_enq(pthread_cond_t cond, pthread_t pthread)
62744963Sjb{
62844963Sjb	pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head);
62944963Sjb
63044963Sjb	/*
63144963Sjb	 * For the common case of all threads having equal priority,
63244963Sjb	 * we perform a quick check against the priority of the thread
63344963Sjb	 * at the tail of the queue.
63444963Sjb	 */
63544963Sjb	if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
63644963Sjb		TAILQ_INSERT_TAIL(&cond->c_queue, pthread, qe);
63744963Sjb	else {
63844963Sjb		tid = TAILQ_FIRST(&cond->c_queue);
63944963Sjb		while (pthread->active_priority <= tid->active_priority)
64044963Sjb			tid = TAILQ_NEXT(tid, qe);
64144963Sjb		TAILQ_INSERT_BEFORE(tid, pthread, qe);
64244963Sjb	}
64348046Sjb	pthread->flags |= PTHREAD_FLAGS_IN_CONDQ;
64444963Sjb}
64513546Sjulian#endif
646