thr_cond.c revision 63355
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 63355 2000-07-17 22:55:05Z jasone $
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		}
28953812Salfred
29053812Salfred		_thread_leave_cancellation_point();
29113546Sjulian	}
29213546Sjulian
29356698Sjasone	_thread_leave_cancellation_point();
29456698Sjasone
29513546Sjulian	/* Return the completion status: */
29613546Sjulian	return (rval);
29713546Sjulian}
29813546Sjulian
29913546Sjulianint
30013546Sjulianpthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
30113546Sjulian		       const struct timespec * abstime)
30213546Sjulian{
30356277Sjasone	int	rval = 0;
30456277Sjasone	int	interrupted = 0;
30513546Sjulian
30656698Sjasone	_thread_enter_cancellation_point();
30756698Sjasone
30863355Sjasone	if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
30963355Sjasone	    abstime->tv_nsec >= 1000000000)
31050601Sdeischen		rval = EINVAL;
31135027Sjb	/*
31263355Sjasone	 * If the condition variable is statically initialized, perform dynamic
31363355Sjasone	 * initialization.
31435027Sjb	 */
31563355Sjasone	else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
31653812Salfred		_thread_enter_cancellation_point();
31753812Salfred
31848046Sjb		/* Lock the condition variable structure: */
31948046Sjb		_SPINLOCK(&(*cond)->lock);
32048046Sjb
32147424Sjb		/*
32247424Sjb		 * If the condvar was statically allocated, properly
32347424Sjb		 * initialize the tail queue.
32447424Sjb		 */
32547424Sjb		if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
32647424Sjb			TAILQ_INIT(&(*cond)->c_queue);
32747424Sjb			(*cond)->c_flags |= COND_FLAGS_INITED;
32847424Sjb		}
32947424Sjb
33017706Sjulian		/* Process according to condition variable type: */
33117706Sjulian		switch ((*cond)->c_type) {
33224827Sjb		/* Fast condition variable: */
33317706Sjulian		case COND_TYPE_FAST:
33444963Sjb			if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
33544963Sjb			    ((*cond)->c_mutex != *mutex))) {
33644963Sjb				/* Return invalid argument error: */
33744963Sjb				rval = EINVAL;
33813546Sjulian
33944963Sjb				/* Unlock the condition variable structure: */
34044963Sjb				_SPINUNLOCK(&(*cond)->lock);
34144963Sjb			} else {
34244963Sjb				/* Set the wakeup time: */
34344963Sjb				_thread_run->wakeup_time.tv_sec =
34444963Sjb				    abstime->tv_sec;
34544963Sjb				_thread_run->wakeup_time.tv_nsec =
34644963Sjb				    abstime->tv_nsec;
34713546Sjulian
34853812Salfred				/* Reset the timeout and interrupted flags: */
34944963Sjb				_thread_run->timeout = 0;
35053812Salfred				_thread_run->interrupted = 0;
35113546Sjulian
35217706Sjulian				/*
35344963Sjb				 * Queue the running thread for the condition
35444963Sjb				 * variable:
35517706Sjulian				 */
35644963Sjb				cond_queue_enq(*cond, _thread_run);
35740974Sdt
35844963Sjb				/* Remember the mutex that is being used: */
35944963Sjb				(*cond)->c_mutex = *mutex;
36013546Sjulian
36144963Sjb				/* Unlock the mutex: */
36244963Sjb				if ((rval = _mutex_cv_unlock(mutex)) != 0) {
36344963Sjb					/*
36444963Sjb					 * Cannot unlock the mutex, so remove
36544963Sjb					 * the running thread from the condition
36644963Sjb					 * variable queue:
36744963Sjb					 */
36844963Sjb					cond_queue_remove(*cond, _thread_run);
36944963Sjb
37044963Sjb					/* Check for no more waiters: */
37144963Sjb					if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
37244963Sjb						(*cond)->c_mutex = NULL;
37344963Sjb
37444963Sjb					/* Unlock the condition variable structure: */
37544963Sjb					_SPINUNLOCK(&(*cond)->lock);
37644963Sjb				} else {
37744963Sjb					/*
37844963Sjb					 * Schedule the next thread and unlock
37944963Sjb					 * the condition variable structure:
38044963Sjb					 */
38144963Sjb					_thread_kern_sched_state_unlock(PS_COND_WAIT,
38244963Sjb				  	     &(*cond)->lock, __FILE__, __LINE__);
38344963Sjb
38453812Salfred					/*
38553812Salfred					 * Check if the wait timedout or was
38653812Salfred					 * interrupted (canceled):
38753812Salfred					 */
38853812Salfred					if ((_thread_run->timeout == 0) &&
38953812Salfred					    (_thread_run->interrupted == 0)) {
39044963Sjb						/* Lock the mutex: */
39144963Sjb						rval = _mutex_cv_lock(mutex);
39253812Salfred
39353812Salfred					} else {
39456277Sjasone						/*
39556277Sjasone						 * Remember if this thread was
39656277Sjasone						 * interrupted:
39756277Sjasone						 */
39856277Sjasone						interrupted = _thread_run->interrupted;
39956277Sjasone
40044963Sjb						/* Lock the condition variable structure: */
40144963Sjb						_SPINLOCK(&(*cond)->lock);
40244963Sjb
40344963Sjb						/*
40444963Sjb						 * The wait timed out; remove
40544963Sjb						 * the thread from the condition
40644963Sjb					 	 * variable queue:
40744963Sjb						 */
40844963Sjb						cond_queue_remove(*cond,
40944963Sjb						    _thread_run);
41044963Sjb
41144963Sjb						/* Check for no more waiters: */
41244963Sjb						if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
41344963Sjb							(*cond)->c_mutex = NULL;
41444963Sjb
41544963Sjb						/* Unock the condition variable structure: */
41644963Sjb						_SPINUNLOCK(&(*cond)->lock);
41744963Sjb
41844963Sjb						/* Return a timeout error: */
41944963Sjb						rval = ETIMEDOUT;
42044963Sjb
42144963Sjb						/*
42253812Salfred						 * Lock the mutex and ignore any
42353812Salfred						 * errors.  Note that even though
42453812Salfred						 * this thread may have been
42553812Salfred						 * canceled, POSIX requires that
42653812Salfred						 * the mutex be reaquired prior
42753812Salfred						 * to cancellation.
42844963Sjb						 */
42944963Sjb						(void)_mutex_cv_lock(mutex);
43044963Sjb					}
43117706Sjulian				}
43213546Sjulian			}
43317706Sjulian			break;
43417706Sjulian
43524827Sjb		/* Trap invalid condition variable types: */
43617706Sjulian		default:
43740974Sdt			/* Unlock the condition variable structure: */
43840974Sdt			_SPINUNLOCK(&(*cond)->lock);
43940974Sdt
44017706Sjulian			/* Return an invalid argument error: */
44131402Salex			rval = EINVAL;
44217706Sjulian			break;
44313546Sjulian		}
44413546Sjulian
44558094Sdeischen		if (interrupted != 0) {
44658094Sdeischen			if (_thread_run->continuation != NULL)
44758094Sdeischen				_thread_run->continuation((void *) _thread_run);
44858094Sdeischen		}
44953812Salfred
45053812Salfred		_thread_leave_cancellation_point();
45113546Sjulian	}
45213546Sjulian
45356698Sjasone	_thread_leave_cancellation_point();
45456698Sjasone
45513546Sjulian	/* Return the completion status: */
45613546Sjulian	return (rval);
45713546Sjulian}
45813546Sjulian
45913546Sjulianint
46013546Sjulianpthread_cond_signal(pthread_cond_t * cond)
46113546Sjulian{
46213546Sjulian	int             rval = 0;
46313546Sjulian	pthread_t       pthread;
46413546Sjulian
46563355Sjasone	if (cond == NULL)
46631402Salex		rval = EINVAL;
46763355Sjasone       /*
46863355Sjasone        * If the condition variable is statically initialized, perform dynamic
46963355Sjasone        * initialization.
47063355Sjasone        */
47163355Sjasone	else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL) == 0)) {
47248046Sjb		/*
47348046Sjb		 * Defer signals to protect the scheduling queues
47448046Sjb		 * from access by the signal handler:
47548046Sjb		 */
47648046Sjb		_thread_kern_sig_defer();
47748046Sjb
47835509Sjb		/* Lock the condition variable structure: */
47936830Sjb		_SPINLOCK(&(*cond)->lock);
48013546Sjulian
48117706Sjulian		/* Process according to condition variable type: */
48217706Sjulian		switch ((*cond)->c_type) {
48324827Sjb		/* Fast condition variable: */
48417706Sjulian		case COND_TYPE_FAST:
48561681Sjasone			if ((pthread = cond_queue_deq(*cond)) != NULL) {
48661681Sjasone				/*
48761681Sjasone				 * Unless the thread is currently suspended,
48861681Sjasone				 * allow it to run.  If the thread is suspended,
48961681Sjasone				 * make a note that the thread isn't in a wait
49061681Sjasone				 * queue any more.
49161681Sjasone				 */
49261681Sjasone				if (pthread->state != PS_SUSPENDED)
49361681Sjasone					PTHREAD_NEW_STATE(pthread,PS_RUNNING);
49461681Sjasone				else
49561681Sjasone					pthread->suspended = SUSP_NOWAIT;
49661681Sjasone			}
49744963Sjb
49844963Sjb			/* Check for no more waiters: */
49944963Sjb			if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
50044963Sjb				(*cond)->c_mutex = NULL;
50117706Sjulian			break;
50217706Sjulian
50324827Sjb		/* Trap invalid condition variable types: */
50417706Sjulian		default:
50517706Sjulian			/* Return an invalid argument error: */
50631402Salex			rval = EINVAL;
50717706Sjulian			break;
50813546Sjulian		}
50913546Sjulian
51035509Sjb		/* Unlock the condition variable structure: */
51136830Sjb		_SPINUNLOCK(&(*cond)->lock);
51248046Sjb
51348046Sjb		/*
51448046Sjb		 * Undefer and handle pending signals, yielding if
51548046Sjb		 * necessary:
51648046Sjb		 */
51748046Sjb		_thread_kern_sig_undefer();
51813546Sjulian	}
51913546Sjulian
52013546Sjulian	/* Return the completion status: */
52113546Sjulian	return (rval);
52213546Sjulian}
52313546Sjulian
52413546Sjulianint
52513546Sjulianpthread_cond_broadcast(pthread_cond_t * cond)
52613546Sjulian{
52713546Sjulian	int             rval = 0;
52813546Sjulian	pthread_t       pthread;
52913546Sjulian
53063355Sjasone	if (cond == NULL)
53135509Sjb		rval = EINVAL;
53263355Sjasone       /*
53363355Sjasone        * If the condition variable is statically initialized, perform dynamic
53463355Sjasone        * initialization.
53563355Sjasone        */
53663355Sjasone	else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL) == 0)) {
53744963Sjb		/*
53848046Sjb		 * Defer signals to protect the scheduling queues
53948046Sjb		 * from access by the signal handler:
54044963Sjb		 */
54148046Sjb		_thread_kern_sig_defer();
54244963Sjb
54335509Sjb		/* Lock the condition variable structure: */
54436830Sjb		_SPINLOCK(&(*cond)->lock);
54513546Sjulian
54635509Sjb		/* Process according to condition variable type: */
54735509Sjb		switch ((*cond)->c_type) {
54835509Sjb		/* Fast condition variable: */
54935509Sjb		case COND_TYPE_FAST:
55035509Sjb			/*
55135509Sjb			 * Enter a loop to bring all threads off the
55235509Sjb			 * condition queue:
55335509Sjb			 */
55444963Sjb			while ((pthread = cond_queue_deq(*cond)) != NULL) {
55561681Sjasone				/*
55661681Sjasone				 * Unless the thread is currently suspended,
55761681Sjasone				 * allow it to run.  If the thread is suspended,
55861681Sjasone				 * make a note that the thread isn't in a wait
55961681Sjasone				 * queue any more.
56061681Sjasone				 */
56161681Sjasone				if (pthread->state != PS_SUSPENDED)
56261681Sjasone					PTHREAD_NEW_STATE(pthread,PS_RUNNING);
56361681Sjasone				else
56461681Sjasone					pthread->suspended = SUSP_NOWAIT;
56535509Sjb			}
56644963Sjb
56744963Sjb			/* There are no more waiting threads: */
56844963Sjb			(*cond)->c_mutex = NULL;
56935509Sjb			break;
57035509Sjb
57135509Sjb		/* Trap invalid condition variable types: */
57235509Sjb		default:
57335509Sjb			/* Return an invalid argument error: */
57435509Sjb			rval = EINVAL;
57535509Sjb			break;
57613546Sjulian		}
57713546Sjulian
57835509Sjb		/* Unlock the condition variable structure: */
57936830Sjb		_SPINUNLOCK(&(*cond)->lock);
58044963Sjb
58148046Sjb		/*
58248046Sjb		 * Undefer and handle pending signals, yielding if
58348046Sjb		 * necessary:
58444963Sjb		 */
58548046Sjb		_thread_kern_sig_undefer();
58613546Sjulian	}
58713546Sjulian
58813546Sjulian	/* Return the completion status: */
58913546Sjulian	return (rval);
59013546Sjulian}
59144963Sjb
59244963Sjb/*
59344963Sjb * Dequeue a waiting thread from the head of a condition queue in
59444963Sjb * descending priority order.
59544963Sjb */
59644963Sjbstatic inline pthread_t
59744963Sjbcond_queue_deq(pthread_cond_t cond)
59844963Sjb{
59944963Sjb	pthread_t pthread;
60044963Sjb
60153812Salfred	while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
60244963Sjb		TAILQ_REMOVE(&cond->c_queue, pthread, qe);
60348046Sjb		pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
60453812Salfred		if ((pthread->timeout == 0) && (pthread->interrupted == 0))
60553812Salfred			/*
60653812Salfred			 * Only exit the loop when we find a thread
60753812Salfred			 * that hasn't timed out or been canceled;
60853812Salfred			 * those threads are already running and don't
60953812Salfred			 * need their run state changed.
61053812Salfred			 */
61153812Salfred			break;
61244963Sjb	}
61344963Sjb
61444963Sjb	return(pthread);
61544963Sjb}
61644963Sjb
61744963Sjb/*
61844963Sjb * Remove a waiting thread from a condition queue in descending priority
61944963Sjb * order.
62044963Sjb */
62144963Sjbstatic inline void
62244963Sjbcond_queue_remove(pthread_cond_t cond, pthread_t pthread)
62344963Sjb{
62444963Sjb	/*
62544963Sjb	 * Because pthread_cond_timedwait() can timeout as well
62644963Sjb	 * as be signaled by another thread, it is necessary to
62744963Sjb	 * guard against removing the thread from the queue if
62844963Sjb	 * it isn't in the queue.
62944963Sjb	 */
63048046Sjb	if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) {
63144963Sjb		TAILQ_REMOVE(&cond->c_queue, pthread, qe);
63248046Sjb		pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
63344963Sjb	}
63444963Sjb}
63544963Sjb
63644963Sjb/*
63744963Sjb * Enqueue a waiting thread to a condition queue in descending priority
63844963Sjb * order.
63944963Sjb */
64044963Sjbstatic inline void
64144963Sjbcond_queue_enq(pthread_cond_t cond, pthread_t pthread)
64244963Sjb{
64344963Sjb	pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head);
64444963Sjb
64544963Sjb	/*
64644963Sjb	 * For the common case of all threads having equal priority,
64744963Sjb	 * we perform a quick check against the priority of the thread
64844963Sjb	 * at the tail of the queue.
64944963Sjb	 */
65044963Sjb	if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
65144963Sjb		TAILQ_INSERT_TAIL(&cond->c_queue, pthread, qe);
65244963Sjb	else {
65344963Sjb		tid = TAILQ_FIRST(&cond->c_queue);
65444963Sjb		while (pthread->active_priority <= tid->active_priority)
65544963Sjb			tid = TAILQ_NEXT(tid, qe);
65644963Sjb		TAILQ_INSERT_BEFORE(tid, pthread, qe);
65744963Sjb	}
65848046Sjb	pthread->flags |= PTHREAD_FLAGS_IN_CONDQ;
65944963Sjb}
66013546Sjulian#endif
661