thr_cond.c revision 112918
1112918Sjeff/*
2112918Sjeff * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3112918Sjeff * All rights reserved.
4112918Sjeff *
5112918Sjeff * Redistribution and use in source and binary forms, with or without
6112918Sjeff * modification, are permitted provided that the following conditions
7112918Sjeff * are met:
8112918Sjeff * 1. Redistributions of source code must retain the above copyright
9112918Sjeff *    notice, this list of conditions and the following disclaimer.
10112918Sjeff * 2. Redistributions in binary form must reproduce the above copyright
11112918Sjeff *    notice, this list of conditions and the following disclaimer in the
12112918Sjeff *    documentation and/or other materials provided with the distribution.
13112918Sjeff * 3. All advertising materials mentioning features or use of this software
14112918Sjeff *    must display the following acknowledgement:
15112918Sjeff *	This product includes software developed by John Birrell.
16112918Sjeff * 4. Neither the name of the author nor the names of any co-contributors
17112918Sjeff *    may be used to endorse or promote products derived from this software
18112918Sjeff *    without specific prior written permission.
19112918Sjeff *
20112918Sjeff * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21112918Sjeff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22112918Sjeff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23112918Sjeff * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24112918Sjeff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25112918Sjeff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26112918Sjeff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27112918Sjeff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28112918Sjeff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29112918Sjeff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30112918Sjeff * SUCH DAMAGE.
31112918Sjeff *
32112918Sjeff * $FreeBSD: head/lib/libthr/thread/thr_cond.c 112918 2003-04-01 03:46:29Z jeff $
33112918Sjeff */
34112918Sjeff#include <stdlib.h>
35112918Sjeff#include <errno.h>
36112918Sjeff#include <string.h>
37112918Sjeff#include <pthread.h>
38112918Sjeff#include "thr_private.h"
39112918Sjeff
40112918Sjeff/*
41112918Sjeff * Prototypes
42112918Sjeff */
43112918Sjeffstatic pthread_t	cond_queue_deq(pthread_cond_t);
44112918Sjeffstatic void		cond_queue_remove(pthread_cond_t, pthread_t);
45112918Sjeffstatic void		cond_queue_enq(pthread_cond_t, pthread_t);
46112918Sjeff
47112918Sjeff__weak_reference(_pthread_cond_init, pthread_cond_init);
48112918Sjeff__weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
49112918Sjeff__weak_reference(_pthread_cond_wait, pthread_cond_wait);
50112918Sjeff__weak_reference(_pthread_cond_timedwait, pthread_cond_timedwait);
51112918Sjeff__weak_reference(_pthread_cond_signal, pthread_cond_signal);
52112918Sjeff__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
53112918Sjeff
54112918Sjeff#define	COND_LOCK(c)						\
55112918Sjeffdo {								\
56112918Sjeff	if (umtx_lock(&(c)->c_lock, curthread->thr_id))		\
57112918Sjeff		abort();					\
58112918Sjeff} while (0)
59112918Sjeff
60112918Sjeff#define	COND_UNLOCK(c)						\
61112918Sjeffdo {								\
62112918Sjeff	if (umtx_unlock(&(c)->c_lock, curthread->thr_id))	\
63112918Sjeff		abort();					\
64112918Sjeff} while (0)
65112918Sjeff
66112918Sjeff
67112918Sjeff/* Reinitialize a condition variable to defaults. */
68112918Sjeffint
69112918Sjeff_cond_reinit(pthread_cond_t *cond)
70112918Sjeff{
71112918Sjeff	if (cond == NULL)
72112918Sjeff		return (EINVAL);
73112918Sjeff
74112918Sjeff	if (*cond == NULL)
75112918Sjeff		return (pthread_cond_init(cond, NULL));
76112918Sjeff
77112918Sjeff	/*
78112918Sjeff	 * Initialize the condition variable structure:
79112918Sjeff	 */
80112918Sjeff	TAILQ_INIT(&(*cond)->c_queue);
81112918Sjeff	(*cond)->c_flags = COND_FLAGS_INITED;
82112918Sjeff	(*cond)->c_type = COND_TYPE_FAST;
83112918Sjeff	(*cond)->c_mutex = NULL;
84112918Sjeff	(*cond)->c_seqno = 0;
85112918Sjeff	bzero(&(*cond)->c_lock, sizeof((*cond)->c_lock));
86112918Sjeff
87112918Sjeff	return (0);
88112918Sjeff}
89112918Sjeff
90112918Sjeffint
91112918Sjeff_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
92112918Sjeff{
93112918Sjeff	enum pthread_cond_type type;
94112918Sjeff	pthread_cond_t	pcond;
95112918Sjeff
96112918Sjeff	if (cond == NULL)
97112918Sjeff		return (EINVAL);
98112918Sjeff
99112918Sjeff	/*
100112918Sjeff	 * Check if a pointer to a condition variable attribute
101112918Sjeff	 * structure was passed by the caller:
102112918Sjeff	 */
103112918Sjeff	if (cond_attr != NULL && *cond_attr != NULL)
104112918Sjeff		type = (*cond_attr)->c_type;
105112918Sjeff	else
106112918Sjeff		/* Default to a fast condition variable: */
107112918Sjeff		type = COND_TYPE_FAST;
108112918Sjeff
109112918Sjeff	/* Process according to condition variable type: */
110112918Sjeff	switch (type) {
111112918Sjeff	case COND_TYPE_FAST:
112112918Sjeff		break;
113112918Sjeff	default:
114112918Sjeff		return (EINVAL);
115112918Sjeff		break;
116112918Sjeff	}
117112918Sjeff
118112918Sjeff	if ((pcond = (pthread_cond_t)
119112918Sjeff	    malloc(sizeof(struct pthread_cond))) == NULL)
120112918Sjeff		return (ENOMEM);
121112918Sjeff	/*
122112918Sjeff	 * Initialise the condition variable
123112918Sjeff	 * structure:
124112918Sjeff	 */
125112918Sjeff	TAILQ_INIT(&pcond->c_queue);
126112918Sjeff	pcond->c_flags |= COND_FLAGS_INITED;
127112918Sjeff	pcond->c_type = type;
128112918Sjeff	pcond->c_mutex = NULL;
129112918Sjeff	pcond->c_seqno = 0;
130112918Sjeff	bzero(&pcond->c_lock, sizeof(pcond->c_lock));
131112918Sjeff
132112918Sjeff	*cond = pcond;
133112918Sjeff
134112918Sjeff	return (0);
135112918Sjeff}
136112918Sjeff
137112918Sjeffint
138112918Sjeff_pthread_cond_destroy(pthread_cond_t *cond)
139112918Sjeff{
140112918Sjeff	struct pthread	*curthread = _get_curthread();
141112918Sjeff
142112918Sjeff	if (cond == NULL || *cond == NULL)
143112918Sjeff		return (EINVAL);
144112918Sjeff
145112918Sjeff	COND_LOCK(*cond);
146112918Sjeff
147112918Sjeff	/*
148112918Sjeff	 * Free the memory allocated for the condition
149112918Sjeff	 * variable structure:
150112918Sjeff	 */
151112918Sjeff	free(*cond);
152112918Sjeff
153112918Sjeff	/*
154112918Sjeff	 * NULL the caller's pointer now that the condition
155112918Sjeff	 * variable has been destroyed:
156112918Sjeff	 */
157112918Sjeff	*cond = NULL;
158112918Sjeff
159112918Sjeff	return (0);
160112918Sjeff}
161112918Sjeff
162112918Sjeffint
163112918Sjeff_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
164112918Sjeff{
165112918Sjeff	int rval;
166112918Sjeff	struct timespec abstime = { 0, 0 };
167112918Sjeff
168112918Sjeff	/*
169112918Sjeff	 * XXXTHR This is a hack.  Make a pthread_cond_common function that
170112918Sjeff	 * accepts NULL so we don't change posix semantics for timedwait.
171112918Sjeff	 */
172112918Sjeff	rval = pthread_cond_timedwait(cond, mutex, &abstime);
173112918Sjeff
174112918Sjeff	/* This should never happen. */
175112918Sjeff	if (rval == ETIMEDOUT)
176112918Sjeff		abort();
177112918Sjeff
178112918Sjeff	return (rval);
179112918Sjeff}
180112918Sjeff
181112918Sjeffint
182112918Sjeff_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
183112918Sjeff		       const struct timespec * abstime)
184112918Sjeff{
185112918Sjeff	struct pthread	*curthread = _get_curthread();
186112918Sjeff	struct timespec *time;
187112918Sjeff	int	rval = 0;
188112918Sjeff	int	done = 0;
189112918Sjeff	int	seqno;
190112918Sjeff	int	mtxrval;
191112918Sjeff
192112918Sjeff
193112918Sjeff	_thread_enter_cancellation_point();
194112918Sjeff
195112918Sjeff	if (abstime == NULL || abstime->tv_nsec >= 1000000000)
196112918Sjeff		return (EINVAL);
197112918Sjeff
198112918Sjeff	if (abstime->tv_sec == 0 && abstime->tv_nsec == 0)
199112918Sjeff		time = NULL;
200112918Sjeff	else
201112918Sjeff		time = abstime;
202112918Sjeff	/*
203112918Sjeff	 * If the condition variable is statically initialized, perform dynamic
204112918Sjeff	 * initialization.
205112918Sjeff	 */
206112918Sjeff	if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
207112918Sjeff		return (rval);
208112918Sjeff
209112918Sjeff
210112918Sjeff	COND_LOCK(*cond);
211112918Sjeff
212112918Sjeff	/*
213112918Sjeff	 * If the condvar was statically allocated, properly
214112918Sjeff	 * initialize the tail queue.
215112918Sjeff	 */
216112918Sjeff	if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
217112918Sjeff		TAILQ_INIT(&(*cond)->c_queue);
218112918Sjeff		(*cond)->c_flags |= COND_FLAGS_INITED;
219112918Sjeff	}
220112918Sjeff
221112918Sjeff	/* Process according to condition variable type. */
222112918Sjeff
223112918Sjeff	switch ((*cond)->c_type) {
224112918Sjeff	/* Fast condition variable: */
225112918Sjeff	case COND_TYPE_FAST:
226112918Sjeff		if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
227112918Sjeff		    ((*cond)->c_mutex != *mutex))) {
228112918Sjeff			COND_UNLOCK(*cond);
229112918Sjeff			rval = EINVAL;
230112918Sjeff			break;
231112918Sjeff		}
232112918Sjeff		/* Remember the mutex */
233112918Sjeff		(*cond)->c_mutex = *mutex;
234112918Sjeff
235112918Sjeff		if ((rval = _mutex_cv_unlock(mutex)) != 0) {
236112918Sjeff			if (rval == -1){
237112918Sjeff				printf("foo");
238112918Sjeff				fflush(stdout);
239112918Sjeff				abort();
240112918Sjeff			}
241112918Sjeff
242112918Sjeff			COND_UNLOCK(*cond);
243112918Sjeff			break;
244112918Sjeff		}
245112918Sjeff		COND_UNLOCK(*cond);
246112918Sjeff
247112918Sjeff		/*
248112918Sjeff		 * We need giant for the queue operations.  It also
249112918Sjeff		 * protects seqno and the pthread flag fields.  This is
250112918Sjeff		 * dropped and reacquired in _thread_suspend().
251112918Sjeff		 */
252112918Sjeff
253112918Sjeff		GIANT_LOCK(curthread);
254112918Sjeff		/*
255112918Sjeff		 * c_seqno is protected by giant.
256112918Sjeff		 */
257112918Sjeff		seqno = (*cond)->c_seqno;
258112918Sjeff
259112918Sjeff		do {
260112918Sjeff			/*
261112918Sjeff			 * Queue the running thread on the condition
262112918Sjeff			 * variable.
263112918Sjeff			 */
264112918Sjeff			cond_queue_enq(*cond, curthread);
265112918Sjeff
266112918Sjeff			if (curthread->cancelflags & PTHREAD_CANCELLING) {
267112918Sjeff				/*
268112918Sjeff				 * POSIX Says that we must relock the mutex
269112918Sjeff				 * even if we're being canceled.
270112918Sjeff				 */
271112918Sjeff				GIANT_UNLOCK(curthread);
272112918Sjeff				_mutex_cv_lock(mutex);
273112918Sjeff				pthread_testcancel();
274112918Sjeff				PANIC("Shouldn't have come back.");
275112918Sjeff			}
276112918Sjeff
277112918Sjeff			PTHREAD_SET_STATE(curthread, PS_COND_WAIT);
278112918Sjeff			rval = _thread_suspend(curthread, time);
279112918Sjeff			if (rval == -1) {
280112918Sjeff				printf("foo");
281112918Sjeff				fflush(stdout);
282112918Sjeff				abort();
283112918Sjeff			}
284112918Sjeff
285112918Sjeff			done = (seqno != (*cond)->c_seqno);
286112918Sjeff
287112918Sjeff			cond_queue_remove(*cond, curthread);
288112918Sjeff
289112918Sjeff		} while ((done == 0) && (rval == 0));
290112918Sjeff		/*
291112918Sjeff		 * If we timed out someone still may have signaled us
292112918Sjeff		 * before we got a chance to run again.  We check for
293112918Sjeff		 * this by looking to see if our state is RUNNING.
294112918Sjeff		 */
295112918Sjeff		if (rval == EAGAIN) {
296112918Sjeff			if (curthread->state != PS_RUNNING) {
297112918Sjeff				PTHREAD_SET_STATE(curthread, PS_RUNNING);
298112918Sjeff				rval = ETIMEDOUT;
299112918Sjeff			} else
300112918Sjeff				rval = 0;
301112918Sjeff		}
302112918Sjeff		GIANT_UNLOCK(curthread);
303112918Sjeff
304112918Sjeff		mtxrval = _mutex_cv_lock(mutex);
305112918Sjeff
306112918Sjeff		/*
307112918Sjeff		 * If the mutex failed return that error, otherwise we're
308112918Sjeff		 * returning ETIMEDOUT.
309112918Sjeff		 */
310112918Sjeff		if (mtxrval == -1) {
311112918Sjeff			printf("foo");
312112918Sjeff			fflush(stdout);
313112918Sjeff			abort();
314112918Sjeff		}
315112918Sjeff		if (mtxrval != 0)
316112918Sjeff			rval = mtxrval;
317112918Sjeff
318112918Sjeff		break;
319112918Sjeff
320112918Sjeff	/* Trap invalid condition variable types: */
321112918Sjeff	default:
322112918Sjeff		COND_UNLOCK(*cond);
323112918Sjeff		rval = EINVAL;
324112918Sjeff		break;
325112918Sjeff	}
326112918Sjeff
327112918Sjeff	/*
328112918Sjeff	 * See if we have to cancel before we retry.  We could be
329112918Sjeff	 * canceled with the mutex held here!
330112918Sjeff	 */
331112918Sjeff	pthread_testcancel();
332112918Sjeff
333112918Sjeff	_thread_leave_cancellation_point();
334112918Sjeff
335112918Sjeff	return (rval);
336112918Sjeff}
337112918Sjeff
338112918Sjeffint
339112918Sjeff_pthread_cond_signal(pthread_cond_t * cond)
340112918Sjeff{
341112918Sjeff	struct pthread	*curthread = _get_curthread();
342112918Sjeff	int             rval = 0;
343112918Sjeff	pthread_t       pthread;
344112918Sjeff
345112918Sjeff	if (cond == NULL)
346112918Sjeff		return (EINVAL);
347112918Sjeff       /*
348112918Sjeff        * If the condition variable is statically initialized, perform dynamic
349112918Sjeff        * initialization.
350112918Sjeff        */
351112918Sjeff	if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
352112918Sjeff		return (rval);
353112918Sjeff
354112918Sjeff
355112918Sjeff	COND_LOCK(*cond);
356112918Sjeff
357112918Sjeff	/* Process according to condition variable type: */
358112918Sjeff	switch ((*cond)->c_type) {
359112918Sjeff	/* Fast condition variable: */
360112918Sjeff	case COND_TYPE_FAST:
361112918Sjeff		GIANT_LOCK(curthread);
362112918Sjeff		(*cond)->c_seqno++;
363112918Sjeff
364112918Sjeff		if ((pthread = cond_queue_deq(*cond)) != NULL) {
365112918Sjeff			/*
366112918Sjeff			 * Wake up the signaled thread:
367112918Sjeff			 */
368112918Sjeff			PTHREAD_NEW_STATE(pthread, PS_RUNNING);
369112918Sjeff		}
370112918Sjeff
371112918Sjeff		GIANT_UNLOCK(curthread);
372112918Sjeff		break;
373112918Sjeff
374112918Sjeff	/* Trap invalid condition variable types: */
375112918Sjeff	default:
376112918Sjeff		rval = EINVAL;
377112918Sjeff		break;
378112918Sjeff	}
379112918Sjeff
380112918Sjeff
381112918Sjeff	COND_UNLOCK(*cond);
382112918Sjeff
383112918Sjeff	return (rval);
384112918Sjeff}
385112918Sjeff
386112918Sjeffint
387112918Sjeff_pthread_cond_broadcast(pthread_cond_t * cond)
388112918Sjeff{
389112918Sjeff	struct pthread	*curthread = _get_curthread();
390112918Sjeff	int             rval = 0;
391112918Sjeff	pthread_t       pthread;
392112918Sjeff
393112918Sjeff	if (cond == NULL)
394112918Sjeff		return (EINVAL);
395112918Sjeff       /*
396112918Sjeff        * If the condition variable is statically initialized, perform dynamic
397112918Sjeff        * initialization.
398112918Sjeff        */
399112918Sjeff	if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0)
400112918Sjeff		return (rval);
401112918Sjeff
402112918Sjeff	COND_LOCK(*cond);
403112918Sjeff
404112918Sjeff	/* Process according to condition variable type: */
405112918Sjeff	switch ((*cond)->c_type) {
406112918Sjeff	/* Fast condition variable: */
407112918Sjeff	case COND_TYPE_FAST:
408112918Sjeff		GIANT_LOCK(curthread);
409112918Sjeff		(*cond)->c_seqno++;
410112918Sjeff
411112918Sjeff		/*
412112918Sjeff		 * Enter a loop to bring all threads off the
413112918Sjeff		 * condition queue:
414112918Sjeff		 */
415112918Sjeff		while ((pthread = cond_queue_deq(*cond)) != NULL) {
416112918Sjeff			/*
417112918Sjeff			 * Wake up the signaled thread:
418112918Sjeff			 */
419112918Sjeff			PTHREAD_NEW_STATE(pthread, PS_RUNNING);
420112918Sjeff		}
421112918Sjeff		GIANT_UNLOCK(curthread);
422112918Sjeff
423112918Sjeff		/* There are no more waiting threads: */
424112918Sjeff		(*cond)->c_mutex = NULL;
425112918Sjeff
426112918Sjeff		break;
427112918Sjeff
428112918Sjeff	/* Trap invalid condition variable types: */
429112918Sjeff	default:
430112918Sjeff		rval = EINVAL;
431112918Sjeff		break;
432112918Sjeff	}
433112918Sjeff
434112918Sjeff	COND_UNLOCK(*cond);
435112918Sjeff
436112918Sjeff
437112918Sjeff	return (rval);
438112918Sjeff}
439112918Sjeff
440112918Sjeffvoid
441112918Sjeff_cond_wait_backout(pthread_t pthread)
442112918Sjeff{
443112918Sjeff	struct pthread	*curthread = _get_curthread();
444112918Sjeff	pthread_cond_t	cond;
445112918Sjeff
446112918Sjeff	cond = pthread->data.cond;
447112918Sjeff	if (cond == NULL)
448112918Sjeff		return;
449112918Sjeff
450112918Sjeff	COND_LOCK(cond);
451112918Sjeff
452112918Sjeff	/* Process according to condition variable type: */
453112918Sjeff	switch (cond->c_type) {
454112918Sjeff	/* Fast condition variable: */
455112918Sjeff	case COND_TYPE_FAST:
456112918Sjeff		GIANT_LOCK(curthread);
457112918Sjeff
458112918Sjeff		cond_queue_remove(cond, pthread);
459112918Sjeff
460112918Sjeff		GIANT_UNLOCK(curthread);
461112918Sjeff		break;
462112918Sjeff
463112918Sjeff	default:
464112918Sjeff		break;
465112918Sjeff	}
466112918Sjeff
467112918Sjeff	COND_UNLOCK(cond);
468112918Sjeff}
469112918Sjeff
470112918Sjeff/*
471112918Sjeff * Dequeue a waiting thread from the head of a condition queue in
472112918Sjeff * descending priority order.
473112918Sjeff */
474112918Sjeffstatic pthread_t
475112918Sjeffcond_queue_deq(pthread_cond_t cond)
476112918Sjeff{
477112918Sjeff	pthread_t pthread;
478112918Sjeff
479112918Sjeff	while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
480112918Sjeff		TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
481112918Sjeff		cond_queue_remove(cond, pthread);
482112918Sjeff		if ((pthread->cancelflags & PTHREAD_CANCELLING) == 0 &&
483112918Sjeff		    pthread->state == PS_COND_WAIT)
484112918Sjeff			/*
485112918Sjeff			 * Only exit the loop when we find a thread
486112918Sjeff			 * that hasn't timed out or been canceled;
487112918Sjeff			 * those threads are already running and don't
488112918Sjeff			 * need their run state changed.
489112918Sjeff			 */
490112918Sjeff			break;
491112918Sjeff	}
492112918Sjeff
493112918Sjeff	return(pthread);
494112918Sjeff}
495112918Sjeff
496112918Sjeff/*
497112918Sjeff * Remove a waiting thread from a condition queue in descending priority
498112918Sjeff * order.
499112918Sjeff */
500112918Sjeffstatic void
501112918Sjeffcond_queue_remove(pthread_cond_t cond, pthread_t pthread)
502112918Sjeff{
503112918Sjeff	/*
504112918Sjeff	 * Because pthread_cond_timedwait() can timeout as well
505112918Sjeff	 * as be signaled by another thread, it is necessary to
506112918Sjeff	 * guard against removing the thread from the queue if
507112918Sjeff	 * it isn't in the queue.
508112918Sjeff	 */
509112918Sjeff	if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) {
510112918Sjeff		TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
511112918Sjeff		pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ;
512112918Sjeff	}
513112918Sjeff	/* Check for no more waiters. */
514112918Sjeff	if (TAILQ_FIRST(&cond->c_queue) == NULL)
515112918Sjeff		cond->c_mutex = NULL;
516112918Sjeff}
517112918Sjeff
518112918Sjeff/*
519112918Sjeff * Enqueue a waiting thread to a condition queue in descending priority
520112918Sjeff * order.
521112918Sjeff */
522112918Sjeffstatic void
523112918Sjeffcond_queue_enq(pthread_cond_t cond, pthread_t pthread)
524112918Sjeff{
525112918Sjeff	pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head);
526112918Sjeff
527112918Sjeff	PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread);
528112918Sjeff
529112918Sjeff	/*
530112918Sjeff	 * For the common case of all threads having equal priority,
531112918Sjeff	 * we perform a quick check against the priority of the thread
532112918Sjeff	 * at the tail of the queue.
533112918Sjeff	 */
534112918Sjeff	if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
535112918Sjeff		TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe);
536112918Sjeff	else {
537112918Sjeff		tid = TAILQ_FIRST(&cond->c_queue);
538112918Sjeff		while (pthread->active_priority <= tid->active_priority)
539112918Sjeff			tid = TAILQ_NEXT(tid, sqe);
540112918Sjeff		TAILQ_INSERT_BEFORE(tid, pthread, sqe);
541112918Sjeff	}
542112918Sjeff	pthread->flags |= PTHREAD_FLAGS_IN_CONDQ;
543112918Sjeff	pthread->data.cond = cond;
544112918Sjeff}
545