thr_cond.c revision 75369
1219019Sgabor/*
2219019Sgabor * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3219019Sgabor * All rights reserved.
4219019Sgabor *
5219019Sgabor * Redistribution and use in source and binary forms, with or without
6219019Sgabor * modification, are permitted provided that the following conditions
7219019Sgabor * are met:
8219019Sgabor * 1. Redistributions of source code must retain the above copyright
9219019Sgabor *    notice, this list of conditions and the following disclaimer.
10219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright
11219019Sgabor *    notice, this list of conditions and the following disclaimer in the
12219019Sgabor *    documentation and/or other materials provided with the distribution.
13219019Sgabor * 3. All advertising materials mentioning features or use of this software
14219019Sgabor *    must display the following acknowledgement:
15219019Sgabor *	This product includes software developed by John Birrell.
16219019Sgabor * 4. Neither the name of the author nor the names of any co-contributors
17219019Sgabor *    may be used to endorse or promote products derived from this software
18219019Sgabor *    without specific prior written permission.
19219019Sgabor *
20219019Sgabor * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23219019Sgabor * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30219019Sgabor * SUCH DAMAGE.
31219019Sgabor *
32219019Sgabor * $FreeBSD: head/lib/libkse/thread/thr_cond.c 75369 2001-04-10 04:19:21Z deischen $
33219019Sgabor */
34219019Sgabor#include <stdlib.h>
35219019Sgabor#include <errno.h>
36219019Sgabor#include <string.h>
37219019Sgabor#include <pthread.h>
38219019Sgabor#include "pthread_private.h"
39219019Sgabor
40219019Sgabor/*
41219019Sgabor * Prototypes
42219019Sgabor */
43219019Sgaborstatic inline pthread_t	cond_queue_deq(pthread_cond_t);
44219019Sgaborstatic inline void	cond_queue_remove(pthread_cond_t, pthread_t);
45219019Sgaborstatic inline void	cond_queue_enq(pthread_cond_t, pthread_t);
46219019Sgabor
47219019Sgabor__weak_reference(_pthread_cond_init, pthread_cond_init);
48219019Sgabor__weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
49219019Sgabor__weak_reference(_pthread_cond_wait, pthread_cond_wait);
50219019Sgabor__weak_reference(_pthread_cond_timedwait, pthread_cond_timedwait);
51219019Sgabor__weak_reference(_pthread_cond_signal, pthread_cond_signal);
52219019Sgabor__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
53219019Sgabor
54219019Sgabor
55219019Sgabor/* Reinitialize a condition variable to defaults. */
56219019Sgaborint
57219019Sgabor_cond_reinit(pthread_cond_t *cond)
58219019Sgabor{
59219019Sgabor	int ret = 0;
60219019Sgabor
61219019Sgabor	if (cond == NULL)
62219019Sgabor		ret = EINVAL;
63219019Sgabor	else if (*cond == NULL)
64219019Sgabor		ret = pthread_cond_init(cond, NULL);
65219019Sgabor	else {
66219019Sgabor		/*
67219019Sgabor		 * Initialize the condition variable structure:
68219019Sgabor		 */
69219019Sgabor		TAILQ_INIT(&(*cond)->c_queue);
70219019Sgabor		(*cond)->c_flags = COND_FLAGS_INITED;
71219019Sgabor		(*cond)->c_type = COND_TYPE_FAST;
72219019Sgabor		(*cond)->c_mutex = NULL;
73219019Sgabor		(*cond)->c_seqno = 0;
74219019Sgabor		memset(&(*cond)->lock, 0, sizeof((*cond)->lock));
75219019Sgabor	}
76219019Sgabor	return (ret);
77219019Sgabor}
78219019Sgabor
79219019Sgaborint
80219019Sgabor_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
81219019Sgabor{
82219019Sgabor	enum pthread_cond_type type;
83219019Sgabor	pthread_cond_t	pcond;
84219019Sgabor	int             rval = 0;
85219019Sgabor
86219019Sgabor	if (cond == NULL)
87219019Sgabor		rval = EINVAL;
88219019Sgabor	else {
89219019Sgabor		/*
90219019Sgabor		 * Check if a pointer to a condition variable attribute
91219019Sgabor		 * structure was passed by the caller:
92219019Sgabor		 */
93219019Sgabor		if (cond_attr != NULL && *cond_attr != NULL) {
94219019Sgabor			/* Default to a fast condition variable: */
95219019Sgabor			type = (*cond_attr)->c_type;
96219019Sgabor		} else {
97219019Sgabor			/* Default to a fast condition variable: */
98219019Sgabor			type = COND_TYPE_FAST;
99219019Sgabor		}
100219019Sgabor
101219019Sgabor		/* Process according to condition variable type: */
102219019Sgabor		switch (type) {
103219019Sgabor		/* Fast condition variable: */
104219019Sgabor		case COND_TYPE_FAST:
105219019Sgabor			/* Nothing to do here. */
106219019Sgabor			break;
107219019Sgabor
108219019Sgabor		/* Trap invalid condition variable types: */
109219019Sgabor		default:
110219019Sgabor			/* Return an invalid argument error: */
111219019Sgabor			rval = EINVAL;
112219019Sgabor			break;
113219019Sgabor		}
114219019Sgabor
115219019Sgabor		/* Check for no errors: */
116219019Sgabor		if (rval == 0) {
117219019Sgabor			if ((pcond = (pthread_cond_t)
118219019Sgabor			    malloc(sizeof(struct pthread_cond))) == NULL) {
119219019Sgabor				rval = ENOMEM;
120219019Sgabor			} else {
121219019Sgabor				/*
122219019Sgabor				 * Initialise the condition variable
123219019Sgabor				 * structure:
124219019Sgabor				 */
125219019Sgabor				TAILQ_INIT(&pcond->c_queue);
126219019Sgabor				pcond->c_flags |= COND_FLAGS_INITED;
127219019Sgabor				pcond->c_type = type;
128219019Sgabor				pcond->c_mutex = NULL;
129219019Sgabor				pcond->c_seqno = 0;
130219019Sgabor				memset(&pcond->lock,0,sizeof(pcond->lock));
131219019Sgabor				*cond = pcond;
132219019Sgabor			}
133219019Sgabor		}
134219019Sgabor	}
135219019Sgabor	/* Return the completion status: */
136219019Sgabor	return (rval);
137219019Sgabor}
138219019Sgabor
139219019Sgaborint
140219019Sgabor_pthread_cond_destroy(pthread_cond_t *cond)
141219019Sgabor{
142219019Sgabor	int             rval = 0;
143219019Sgabor
144219019Sgabor	if (cond == NULL || *cond == NULL)
145219019Sgabor		rval = EINVAL;
146219019Sgabor	else {
147219019Sgabor		/* Lock the condition variable structure: */
148219019Sgabor		_SPINLOCK(&(*cond)->lock);
149219019Sgabor
150219019Sgabor		/*
151219019Sgabor		 * Free the memory allocated for the condition
152219019Sgabor		 * variable structure:
153219019Sgabor		 */
154219019Sgabor		free(*cond);
155219019Sgabor
156219019Sgabor		/*
157219019Sgabor		 * NULL the caller's pointer now that the condition
158219019Sgabor		 * variable has been destroyed:
159219019Sgabor		 */
160219019Sgabor		*cond = NULL;
161219019Sgabor	}
162219019Sgabor	/* Return the completion status: */
163219019Sgabor	return (rval);
164219019Sgabor}
165219019Sgabor
166219019Sgaborint
167219019Sgabor_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
168219019Sgabor{
169219019Sgabor	struct pthread	*curthread = _get_curthread();
170219019Sgabor	int	rval = 0;
171219019Sgabor	int	done = 0;
172219019Sgabor	int	interrupted = 0;
173219019Sgabor	int	unlock_mutex = 1;
174219019Sgabor	int	seqno;
175219019Sgabor
176219019Sgabor	_thread_enter_cancellation_point();
177219019Sgabor
178219019Sgabor	if (cond == NULL)
179219019Sgabor		return (EINVAL);
180219019Sgabor
181219019Sgabor	/*
182219019Sgabor	 * If the condition variable is statically initialized,
183219019Sgabor	 * perform the dynamic initialization:
184219019Sgabor	 */
185219019Sgabor	if (*cond == NULL &&
186219019Sgabor	    (rval = pthread_cond_init(cond, NULL)) != 0)
187219019Sgabor		return (rval);
188219019Sgabor
189219019Sgabor	/*
190219019Sgabor	 * Enter a loop waiting for a condition signal or broadcast
191219019Sgabor	 * to wake up this thread.  A loop is needed in case the waiting
192219019Sgabor	 * thread is interrupted by a signal to execute a signal handler.
193219019Sgabor	 * It is not (currently) possible to remain in the waiting queue
194219019Sgabor	 * while running a handler.  Instead, the thread is interrupted
195219019Sgabor	 * and backed out of the waiting queue prior to executing the
196219019Sgabor	 * signal handler.
197219019Sgabor	 */
198219019Sgabor	do {
199219019Sgabor		/* Lock the condition variable structure: */
200219019Sgabor		_SPINLOCK(&(*cond)->lock);
201219019Sgabor
202219019Sgabor		/*
203219019Sgabor		 * If the condvar was statically allocated, properly
204219019Sgabor		 * initialize the tail queue.
205219019Sgabor		 */
206219019Sgabor		if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
207219019Sgabor			TAILQ_INIT(&(*cond)->c_queue);
208219019Sgabor			(*cond)->c_flags |= COND_FLAGS_INITED;
209219019Sgabor		}
210219019Sgabor
211219019Sgabor		/* Process according to condition variable type: */
212219019Sgabor		switch ((*cond)->c_type) {
213219019Sgabor		/* Fast condition variable: */
214219019Sgabor		case COND_TYPE_FAST:
215219019Sgabor			if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
216219019Sgabor			    ((*cond)->c_mutex != *mutex))) {
217219019Sgabor				/* Unlock the condition variable structure: */
218219019Sgabor				_SPINUNLOCK(&(*cond)->lock);
219219019Sgabor
220219019Sgabor				/* Return invalid argument error: */
221219019Sgabor				rval = EINVAL;
222219019Sgabor			} else {
223219019Sgabor				/* Reset the timeout and interrupted flags: */
224219019Sgabor				curthread->timeout = 0;
225219019Sgabor				curthread->interrupted = 0;
226219019Sgabor
227219019Sgabor				/*
228219019Sgabor				 * Queue the running thread for the condition
229219019Sgabor				 * variable:
230219019Sgabor				 */
231219019Sgabor				cond_queue_enq(*cond, curthread);
232219019Sgabor
233219019Sgabor				/* Remember the mutex and sequence number: */
234219019Sgabor				(*cond)->c_mutex = *mutex;
235219019Sgabor				seqno = (*cond)->c_seqno;
236219019Sgabor
237219019Sgabor				/* Wait forever: */
238219019Sgabor				curthread->wakeup_time.tv_sec = -1;
239219019Sgabor
240219019Sgabor				/* Unlock the mutex: */
241219019Sgabor				if ((unlock_mutex != 0) &&
242219019Sgabor				    ((rval = _mutex_cv_unlock(mutex)) != 0)) {
243219019Sgabor					/*
244219019Sgabor					 * Cannot unlock the mutex, so remove
245219019Sgabor					 * the running thread from the condition
246219019Sgabor					 * variable queue:
247219019Sgabor					 */
248219019Sgabor					cond_queue_remove(*cond, curthread);
249219019Sgabor
250219019Sgabor					/* Check for no more waiters: */
251219019Sgabor					if (TAILQ_FIRST(&(*cond)->c_queue) ==
252219019Sgabor					    NULL)
253219019Sgabor						(*cond)->c_mutex = NULL;
254219019Sgabor
255219019Sgabor					/* Unlock the condition variable structure: */
256219019Sgabor					_SPINUNLOCK(&(*cond)->lock);
257219019Sgabor				}
258219019Sgabor				else {
259219019Sgabor					/*
260219019Sgabor					 * Don't unlock the mutex in the event
261219019Sgabor					 * this thread has to be requeued in
262219019Sgabor					 * condition variable queue:
263219019Sgabor					 */
264219019Sgabor					unlock_mutex = 0;
265219019Sgabor
266219019Sgabor					/*
267219019Sgabor					 * Schedule the next thread and unlock
268219019Sgabor					 * the condition variable structure:
269219019Sgabor					 */
270219019Sgabor					_thread_kern_sched_state_unlock(PS_COND_WAIT,
271219019Sgabor				    	    &(*cond)->lock, __FILE__, __LINE__);
272219019Sgabor
273219019Sgabor					done = (seqno != (*cond)->c_seqno);
274219019Sgabor
275219019Sgabor					if ((curthread->flags &
276219019Sgabor					    PTHREAD_FLAGS_IN_CONDQ) != 0) {
277219019Sgabor						/*
278219019Sgabor						 * Lock the condition variable
279219019Sgabor						 * while removing the thread.
280219019Sgabor						 */
281219019Sgabor						_SPINLOCK(&(*cond)->lock);
282219019Sgabor
283219019Sgabor						cond_queue_remove(*cond,
284219019Sgabor						    curthread);
285219019Sgabor
286219019Sgabor						/* Check for no more waiters: */
287219019Sgabor						if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
288219019Sgabor							(*cond)->c_mutex = NULL;
289219019Sgabor
290219019Sgabor						_SPINUNLOCK(&(*cond)->lock);
291219019Sgabor					}
292219019Sgabor
293219019Sgabor					/*
294219019Sgabor					 * Save the interrupted flag; locking
295219019Sgabor					 * the mutex will destroy it.
296219019Sgabor					 */
297219019Sgabor					interrupted = curthread->interrupted;
298219019Sgabor
299219019Sgabor					/*
300219019Sgabor					 * Note that even though this thread may have
301219019Sgabor					 * been canceled, POSIX requires that the mutex
302219019Sgabor					 * be reaquired prior to cancellation.
303219019Sgabor					 */
304219019Sgabor					rval = _mutex_cv_lock(mutex);
305219019Sgabor				}
306219019Sgabor			}
307219019Sgabor			break;
308219019Sgabor
309219019Sgabor		/* Trap invalid condition variable types: */
310219019Sgabor		default:
311219019Sgabor			/* Unlock the condition variable structure: */
312219019Sgabor			_SPINUNLOCK(&(*cond)->lock);
313219019Sgabor
314219019Sgabor			/* Return an invalid argument error: */
315219019Sgabor			rval = EINVAL;
316219019Sgabor			break;
317219019Sgabor		}
318219019Sgabor
319219019Sgabor		if ((interrupted != 0) && (curthread->continuation != NULL))
320219019Sgabor			curthread->continuation((void *) curthread);
321219019Sgabor	} while ((done == 0) && (rval == 0));
322219019Sgabor
323219019Sgabor	_thread_leave_cancellation_point();
324219019Sgabor
325219019Sgabor	/* Return the completion status: */
326219019Sgabor	return (rval);
327219019Sgabor}
328219019Sgabor
329219019Sgaborint
330219019Sgabor_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
331219019Sgabor		       const struct timespec * abstime)
332219019Sgabor{
333219019Sgabor	struct pthread	*curthread = _get_curthread();
334219019Sgabor	int	rval = 0;
335219019Sgabor	int	done = 0;
336219019Sgabor	int	interrupted = 0;
337219019Sgabor	int	unlock_mutex = 1;
338219019Sgabor	int	seqno;
339219019Sgabor
340219019Sgabor	_thread_enter_cancellation_point();
341219019Sgabor
342219019Sgabor	if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
343219019Sgabor	    abstime->tv_nsec >= 1000000000)
344219019Sgabor		return (EINVAL);
345219019Sgabor	/*
346219019Sgabor	 * If the condition variable is statically initialized, perform dynamic
347219019Sgabor	 * initialization.
348219019Sgabor	 */
349219019Sgabor	if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
350219019Sgabor		return (rval);
351219019Sgabor
352219019Sgabor	/*
353219019Sgabor	 * Enter a loop waiting for a condition signal or broadcast
354219019Sgabor	 * to wake up this thread.  A loop is needed in case the waiting
355219019Sgabor	 * thread is interrupted by a signal to execute a signal handler.
356219019Sgabor	 * It is not (currently) possible to remain in the waiting queue
357219019Sgabor	 * while running a handler.  Instead, the thread is interrupted
358219019Sgabor	 * and backed out of the waiting queue prior to executing the
359219019Sgabor	 * signal handler.
360219019Sgabor	 */
361219019Sgabor	do {
362219019Sgabor		/* Lock the condition variable structure: */
363219019Sgabor		_SPINLOCK(&(*cond)->lock);
364219019Sgabor
365219019Sgabor		/*
366219019Sgabor		 * If the condvar was statically allocated, properly
367219019Sgabor		 * initialize the tail queue.
368219019Sgabor		 */
369219019Sgabor		if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
370219019Sgabor			TAILQ_INIT(&(*cond)->c_queue);
371219019Sgabor			(*cond)->c_flags |= COND_FLAGS_INITED;
372219019Sgabor		}
373219019Sgabor
374219019Sgabor		/* Process according to condition variable type: */
375219019Sgabor		switch ((*cond)->c_type) {
376219019Sgabor		/* Fast condition variable: */
377219019Sgabor		case COND_TYPE_FAST:
378219019Sgabor			if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
379219019Sgabor			    ((*cond)->c_mutex != *mutex))) {
380219019Sgabor				/* Return invalid argument error: */
381219019Sgabor				rval = EINVAL;
382219019Sgabor
383219019Sgabor				/* Unlock the condition variable structure: */
384219019Sgabor				_SPINUNLOCK(&(*cond)->lock);
385219019Sgabor			} else {
386219019Sgabor				/* Set the wakeup time: */
387219019Sgabor				curthread->wakeup_time.tv_sec =
388219019Sgabor				    abstime->tv_sec;
389219019Sgabor				curthread->wakeup_time.tv_nsec =
390219019Sgabor				    abstime->tv_nsec;
391219019Sgabor
392219019Sgabor				/* Reset the timeout and interrupted flags: */
393219019Sgabor				curthread->timeout = 0;
394219019Sgabor				curthread->interrupted = 0;
395219019Sgabor
396219019Sgabor				/*
397219019Sgabor				 * Queue the running thread for the condition
398219019Sgabor				 * variable:
399219019Sgabor				 */
400219019Sgabor				cond_queue_enq(*cond, curthread);
401219019Sgabor
402219019Sgabor				/* Remember the mutex and sequence number: */
403219019Sgabor				(*cond)->c_mutex = *mutex;
404219019Sgabor				seqno = (*cond)->c_seqno;
405219019Sgabor
406219019Sgabor				/* Unlock the mutex: */
407219019Sgabor				if ((unlock_mutex != 0) &&
408219019Sgabor				   ((rval = _mutex_cv_unlock(mutex)) != 0)) {
409219019Sgabor					/*
410219019Sgabor					 * Cannot unlock the mutex, so remove
411219019Sgabor					 * the running thread from the condition
412219019Sgabor					 * variable queue:
413219019Sgabor					 */
414219019Sgabor					cond_queue_remove(*cond, curthread);
415219019Sgabor
416219019Sgabor					/* Check for no more waiters: */
417219019Sgabor					if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
418						(*cond)->c_mutex = NULL;
419
420					/* Unlock the condition variable structure: */
421					_SPINUNLOCK(&(*cond)->lock);
422				} else {
423					/*
424					 * Don't unlock the mutex in the event
425					 * this thread has to be requeued in
426					 * condition variable queue:
427					 */
428					unlock_mutex = 0;
429
430					/*
431					 * Schedule the next thread and unlock
432					 * the condition variable structure:
433					 */
434					_thread_kern_sched_state_unlock(PS_COND_WAIT,
435				  	     &(*cond)->lock, __FILE__, __LINE__);
436
437					done = (seqno != (*cond)->c_seqno);
438
439					/*
440					 * Check if the wait timedout, was
441					 * interrupted (canceled), or needs to
442					 * be resumed after handling a signal.
443					 */
444					if ((curthread->timeout == 0) &&
445					    (curthread->interrupted == 0) &&
446					    (done != 0)) {
447						/* Lock the mutex: */
448						rval = _mutex_cv_lock(mutex);
449					} else {
450						/* Lock the CV structure: */
451						_SPINLOCK(&(*cond)->lock);
452
453						/*
454						 * The wait timed out; remove
455						 * the thread from the condition
456						 * variable queue:
457						 */
458						cond_queue_remove(*cond,
459						    curthread);
460
461						/* Check for no more waiters: */
462						if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
463							(*cond)->c_mutex = NULL;
464
465						/* Unock the CV structure: */
466						_SPINUNLOCK(&(*cond)->lock);
467
468						/* Return a timeout error: */
469						if (curthread->timeout != 0)
470							rval = ETIMEDOUT;
471						/*
472						 * Save the interrupted flag;
473						 * locking the mutex will
474						 * destroy it.
475						 */
476						interrupted = curthread->interrupted;
477
478						/*
479						 * Lock the mutex and ignore any
480						 * errors.  Note that even though
481						 * this thread may have been
482						 * canceled, POSIX requires that
483						 * the mutex be reaquired prior
484						 * to cancellation.
485						 */
486						(void)_mutex_cv_lock(mutex);
487					}
488				}
489			}
490			break;
491
492		/* Trap invalid condition variable types: */
493		default:
494			/* Unlock the condition variable structure: */
495			_SPINUNLOCK(&(*cond)->lock);
496
497			/* Return an invalid argument error: */
498			rval = EINVAL;
499			break;
500		}
501
502		if ((interrupted != 0) && (curthread->continuation != NULL))
503			curthread->continuation((void *) curthread);
504	} while ((done == 0) && (rval == 0));
505
506	_thread_leave_cancellation_point();
507
508	/* Return the completion status: */
509	return (rval);
510}
511
512int
513_pthread_cond_signal(pthread_cond_t * cond)
514{
515	int             rval = 0;
516	pthread_t       pthread;
517
518	if (cond == NULL)
519		rval = EINVAL;
520       /*
521        * If the condition variable is statically initialized, perform dynamic
522        * initialization.
523        */
524	else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
525		/*
526		 * Defer signals to protect the scheduling queues
527		 * from access by the signal handler:
528		 */
529		_thread_kern_sig_defer();
530
531		/* Lock the condition variable structure: */
532		_SPINLOCK(&(*cond)->lock);
533
534		/* Process according to condition variable type: */
535		switch ((*cond)->c_type) {
536		/* Fast condition variable: */
537		case COND_TYPE_FAST:
538			/* Increment the sequence number: */
539			(*cond)->c_seqno++;
540
541			if ((pthread = cond_queue_deq(*cond)) != NULL) {
542				/*
543				 * Unless the thread is currently suspended,
544				 * allow it to run.  If the thread is suspended,
545				 * make a note that the thread isn't in a wait
546				 * queue any more.
547				 */
548				if (pthread->state != PS_SUSPENDED)
549					PTHREAD_NEW_STATE(pthread,PS_RUNNING);
550				else
551					pthread->suspended = SUSP_NOWAIT;
552			}
553
554			/* Check for no more waiters: */
555			if (TAILQ_FIRST(&(*cond)->c_queue) == NULL)
556				(*cond)->c_mutex = NULL;
557			break;
558
559		/* Trap invalid condition variable types: */
560		default:
561			/* Return an invalid argument error: */
562			rval = EINVAL;
563			break;
564		}
565
566		/* Unlock the condition variable structure: */
567		_SPINUNLOCK(&(*cond)->lock);
568
569		/*
570		 * Undefer and handle pending signals, yielding if
571		 * necessary:
572		 */
573		_thread_kern_sig_undefer();
574	}
575
576	/* Return the completion status: */
577	return (rval);
578}
579
580int
581_pthread_cond_broadcast(pthread_cond_t * cond)
582{
583	int             rval = 0;
584	pthread_t       pthread;
585
586	if (cond == NULL)
587		rval = EINVAL;
588       /*
589        * If the condition variable is statically initialized, perform dynamic
590        * initialization.
591        */
592	else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) {
593		/*
594		 * Defer signals to protect the scheduling queues
595		 * from access by the signal handler:
596		 */
597		_thread_kern_sig_defer();
598
599		/* Lock the condition variable structure: */
600		_SPINLOCK(&(*cond)->lock);
601
602		/* Process according to condition variable type: */
603		switch ((*cond)->c_type) {
604		/* Fast condition variable: */
605		case COND_TYPE_FAST:
606			/* Increment the sequence number: */
607			(*cond)->c_seqno++;
608
609			/*
610			 * Enter a loop to bring all threads off the
611			 * condition queue:
612			 */
613			while ((pthread = cond_queue_deq(*cond)) != NULL) {
614				/*
615				 * Unless the thread is currently suspended,
616				 * allow it to run.  If the thread is suspended,
617				 * make a note that the thread isn't in a wait
618				 * queue any more.
619				 */
620				if (pthread->state != PS_SUSPENDED)
621					PTHREAD_NEW_STATE(pthread,PS_RUNNING);
622				else
623					pthread->suspended = SUSP_NOWAIT;
624			}
625
626			/* There are no more waiting threads: */
627			(*cond)->c_mutex = NULL;
628			break;
629
630		/* Trap invalid condition variable types: */
631		default:
632			/* Return an invalid argument error: */
633			rval = EINVAL;
634			break;
635		}
636
637		/* Unlock the condition variable structure: */
638		_SPINUNLOCK(&(*cond)->lock);
639
640		/*
641		 * Undefer and handle pending signals, yielding if
642		 * necessary:
643		 */
644		_thread_kern_sig_undefer();
645	}
646
647	/* Return the completion status: */
648	return (rval);
649}
650
651void
652_cond_wait_backout(pthread_t pthread)
653{
654	pthread_cond_t	cond;
655
656	cond = pthread->data.cond;
657	if (cond != NULL) {
658		/*
659		 * Defer signals to protect the scheduling queues
660		 * from access by the signal handler:
661		 */
662		_thread_kern_sig_defer();
663
664		/* Lock the condition variable structure: */
665		_SPINLOCK(&cond->lock);
666
667		/* Process according to condition variable type: */
668		switch (cond->c_type) {
669		/* Fast condition variable: */
670		case COND_TYPE_FAST:
671			cond_queue_remove(cond, pthread);
672
673			/* Check for no more waiters: */
674			if (TAILQ_FIRST(&cond->c_queue) == NULL)
675				cond->c_mutex = NULL;
676			break;
677
678		default:
679			break;
680		}
681
682		/* Unlock the condition variable structure: */
683		_SPINUNLOCK(&cond->lock);
684
685		/*
686		 * Undefer and handle pending signals, yielding if
687		 * necessary:
688		 */
689		_thread_kern_sig_undefer();
690	}
691}
692
693/*
694 * Dequeue a waiting thread from the head of a condition queue in
695 * descending priority order.
696 */
697static inline pthread_t
698cond_queue_deq(pthread_cond_t cond)
699{
700	pthread_t pthread;
701
702	while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
703		TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
704		pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
705		if ((pthread->timeout == 0) && (pthread->interrupted == 0))
706			/*
707			 * Only exit the loop when we find a thread
708			 * that hasn't timed out or been canceled;
709			 * those threads are already running and don't
710			 * need their run state changed.
711			 */
712			break;
713	}
714
715	return(pthread);
716}
717
718/*
719 * Remove a waiting thread from a condition queue in descending priority
720 * order.
721 */
722static inline void
723cond_queue_remove(pthread_cond_t cond, pthread_t pthread)
724{
725	/*
726	 * Because pthread_cond_timedwait() can timeout as well
727	 * as be signaled by another thread, it is necessary to
728	 * guard against removing the thread from the queue if
729	 * it isn't in the queue.
730	 */
731	if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) {
732		TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
733		pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
734	}
735}
736
737/*
738 * Enqueue a waiting thread to a condition queue in descending priority
739 * order.
740 */
741static inline void
742cond_queue_enq(pthread_cond_t cond, pthread_t pthread)
743{
744	pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head);
745
746	PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread);
747
748	/*
749	 * For the common case of all threads having equal priority,
750	 * we perform a quick check against the priority of the thread
751	 * at the tail of the queue.
752	 */
753	if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
754		TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe);
755	else {
756		tid = TAILQ_FIRST(&cond->c_queue);
757		while (pthread->active_priority <= tid->active_priority)
758			tid = TAILQ_NEXT(tid, sqe);
759		TAILQ_INSERT_BEFORE(tid, pthread, sqe);
760	}
761	pthread->flags |= PTHREAD_FLAGS_IN_CONDQ;
762	pthread->data.cond = cond;
763}
764