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.
13165967Simp * 3. Neither the name of the author nor the names of any co-contributors
1413546Sjulian *    may be used to endorse or promote products derived from this software
1513546Sjulian *    without specific prior written permission.
1613546Sjulian *
1713546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
1813546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1913546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2044963Sjb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2113546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2213546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2313546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2413546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2513546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2613546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2713546Sjulian * SUCH DAMAGE.
2813546Sjulian *
2950476Speter * $FreeBSD$
3013546Sjulian */
31174112Sdeischen
32174112Sdeischen#include "namespace.h"
3313546Sjulian#include <stdlib.h>
3413546Sjulian#include <errno.h>
3536830Sjb#include <string.h>
3613546Sjulian#include <pthread.h>
37174112Sdeischen#include "un-namespace.h"
38103388Smini#include "thr_private.h"
3913546Sjulian
40113658Sdeischen#define	THR_IN_CONDQ(thr)	(((thr)->sflags & THR_FLAGS_IN_SYNCQ) != 0)
41113658Sdeischen#define	THR_CONDQ_SET(thr)	(thr)->sflags |= THR_FLAGS_IN_SYNCQ
42113658Sdeischen#define	THR_CONDQ_CLEAR(thr)	(thr)->sflags &= ~THR_FLAGS_IN_SYNCQ
43113658Sdeischen
4444963Sjb/*
4544963Sjb * Prototypes
4644963Sjb */
47113658Sdeischenstatic inline struct pthread	*cond_queue_deq(pthread_cond_t);
48113658Sdeischenstatic inline void		cond_queue_remove(pthread_cond_t, pthread_t);
49113658Sdeischenstatic inline void		cond_queue_enq(pthread_cond_t, pthread_t);
50139023Sdeischenstatic void			cond_wait_backout(void *);
51139023Sdeischenstatic inline void		check_continuation(struct pthread *,
52139023Sdeischen				    struct pthread_cond *, pthread_mutex_t *);
5344963Sjb
54174112Sdeischenint __pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
55174112Sdeischenint __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
56174112Sdeischen		       const struct timespec *abstime);
57174112Sdeischen
58115173Sdeischen/*
59115173Sdeischen * Double underscore versions are cancellation points.  Single underscore
60115173Sdeischen * versions are not and are provided for libc internal usage (which
61115173Sdeischen * shouldn't introduce cancellation points).
62115173Sdeischen */
63115173Sdeischen__weak_reference(__pthread_cond_wait, pthread_cond_wait);
64115173Sdeischen__weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait);
65115173Sdeischen
6675369Sdeischen__weak_reference(_pthread_cond_init, pthread_cond_init);
6775369Sdeischen__weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
6875369Sdeischen__weak_reference(_pthread_cond_signal, pthread_cond_signal);
6975369Sdeischen__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
7071581Sdeischen
7171581Sdeischen
7248046Sjbint
7371581Sdeischen_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
7413546Sjulian{
7513546Sjulian	enum pthread_cond_type type;
7617706Sjulian	pthread_cond_t	pcond;
77113658Sdeischen	int		flags;
7813546Sjulian	int             rval = 0;
7913546Sjulian
8035509Sjb	if (cond == NULL)
8131402Salex		rval = EINVAL;
8235509Sjb	else {
8317706Sjulian		/*
8424827Sjb		 * Check if a pointer to a condition variable attribute
8524827Sjb		 * structure was passed by the caller:
8617706Sjulian		 */
8717706Sjulian		if (cond_attr != NULL && *cond_attr != NULL) {
8817706Sjulian			/* Default to a fast condition variable: */
8917706Sjulian			type = (*cond_attr)->c_type;
90113658Sdeischen			flags = (*cond_attr)->c_flags;
9117706Sjulian		} else {
9217706Sjulian			/* Default to a fast condition variable: */
9317706Sjulian			type = COND_TYPE_FAST;
94113658Sdeischen			flags = 0;
9517706Sjulian		}
9613546Sjulian
9717706Sjulian		/* Process according to condition variable type: */
9817706Sjulian		switch (type) {
9924827Sjb		/* Fast condition variable: */
10017706Sjulian		case COND_TYPE_FAST:
10117706Sjulian			/* Nothing to do here. */
10217706Sjulian			break;
10313546Sjulian
10424827Sjb		/* Trap invalid condition variable types: */
10517706Sjulian		default:
10617706Sjulian			/* Return an invalid argument error: */
10731402Salex			rval = EINVAL;
10817706Sjulian			break;
10917706Sjulian		}
11013546Sjulian
11117706Sjulian		/* Check for no errors: */
11217706Sjulian		if (rval == 0) {
11324827Sjb			if ((pcond = (pthread_cond_t)
11424827Sjb			    malloc(sizeof(struct pthread_cond))) == NULL) {
11531402Salex				rval = ENOMEM;
116113658Sdeischen			} else if (_lock_init(&pcond->c_lock, LCK_ADAPTIVE,
117173967Sjasone			    _thr_lock_wait, _thr_lock_wakeup, calloc) != 0) {
118113658Sdeischen				free(pcond);
119113658Sdeischen				rval = ENOMEM;
12017706Sjulian			} else {
12117706Sjulian				/*
12217706Sjulian				 * Initialise the condition variable
12317706Sjulian				 * structure:
12417706Sjulian				 */
12544963Sjb				TAILQ_INIT(&pcond->c_queue);
126120069Sdavidxu				pcond->c_flags = COND_FLAGS_INITED;
12717706Sjulian				pcond->c_type = type;
12844963Sjb				pcond->c_mutex = NULL;
12968516Sdeischen				pcond->c_seqno = 0;
13017706Sjulian				*cond = pcond;
13117706Sjulian			}
13217706Sjulian		}
13313546Sjulian	}
13413546Sjulian	/* Return the completion status: */
13513546Sjulian	return (rval);
13613546Sjulian}
13713546Sjulian
13813546Sjulianint
13971581Sdeischen_pthread_cond_destroy(pthread_cond_t *cond)
14013546Sjulian{
141113658Sdeischen	struct pthread_cond	*cv;
142113658Sdeischen	struct pthread		*curthread = _get_curthread();
143113658Sdeischen	int			rval = 0;
14413546Sjulian
14535509Sjb	if (cond == NULL || *cond == NULL)
14631402Salex		rval = EINVAL;
14735509Sjb	else {
14835509Sjb		/* Lock the condition variable structure: */
149113658Sdeischen		THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
15013546Sjulian
15135509Sjb		/*
152113658Sdeischen		 * NULL the caller's pointer now that the condition
153113658Sdeischen		 * variable has been destroyed:
154113658Sdeischen		 */
155113658Sdeischen		cv = *cond;
156113658Sdeischen		*cond = NULL;
157113658Sdeischen
158113658Sdeischen		/* Unlock the condition variable structure: */
159113658Sdeischen		THR_LOCK_RELEASE(curthread, &cv->c_lock);
160113658Sdeischen
161115761Sdavidxu		/* Free the cond lock structure: */
162115761Sdavidxu		_lock_destroy(&cv->c_lock);
163115761Sdavidxu
164113658Sdeischen		/*
16535509Sjb		 * Free the memory allocated for the condition
16635509Sjb		 * variable structure:
16735509Sjb		 */
168113658Sdeischen		free(cv);
16917706Sjulian
17013546Sjulian	}
17113546Sjulian	/* Return the completion status: */
17213546Sjulian	return (rval);
17313546Sjulian}
17413546Sjulian
17513546Sjulianint
17671581Sdeischen_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
17713546Sjulian{
17871581Sdeischen	struct pthread	*curthread = _get_curthread();
17956277Sjasone	int	rval = 0;
18068516Sdeischen	int	done = 0;
181139023Sdeischen	int	mutex_locked = 1;
18268516Sdeischen	int	seqno;
18313546Sjulian
184115173Sdeischen	if (cond == NULL)
18568516Sdeischen		return (EINVAL);
18635027Sjb
18735027Sjb	/*
18835027Sjb	 * If the condition variable is statically initialized,
18935027Sjb	 * perform the dynamic initialization:
19035027Sjb	 */
19168516Sdeischen	if (*cond == NULL &&
192174112Sdeischen	    (rval = _pthread_cond_init(cond, NULL)) != 0)
19368516Sdeischen		return (rval);
19468516Sdeischen
195115278Sdeischen	if (!_kse_isthreaded())
196115278Sdeischen		_kse_setthreaded(1);
197115278Sdeischen
19868516Sdeischen	/*
19968516Sdeischen	 * Enter a loop waiting for a condition signal or broadcast
20068516Sdeischen	 * to wake up this thread.  A loop is needed in case the waiting
20168516Sdeischen	 * thread is interrupted by a signal to execute a signal handler.
20268516Sdeischen	 * It is not (currently) possible to remain in the waiting queue
20368516Sdeischen	 * while running a handler.  Instead, the thread is interrupted
20468516Sdeischen	 * and backed out of the waiting queue prior to executing the
20568516Sdeischen	 * signal handler.
20668516Sdeischen	 */
207139023Sdeischen
208139023Sdeischen	/* Lock the condition variable structure: */
209139023Sdeischen	THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
210139023Sdeischen	seqno = (*cond)->c_seqno;
21168516Sdeischen	do {
21247424Sjb		/*
21347424Sjb		 * If the condvar was statically allocated, properly
21447424Sjb		 * initialize the tail queue.
21547424Sjb		 */
21647424Sjb		if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
21747424Sjb			TAILQ_INIT(&(*cond)->c_queue);
21847424Sjb			(*cond)->c_flags |= COND_FLAGS_INITED;
21947424Sjb		}
22047424Sjb
22117706Sjulian		/* Process according to condition variable type: */
22217706Sjulian		switch ((*cond)->c_type) {
22324827Sjb		/* Fast condition variable: */
22417706Sjulian		case COND_TYPE_FAST:
22544963Sjb			if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
22644963Sjb			    ((*cond)->c_mutex != *mutex))) {
22744963Sjb				/* Return invalid argument error: */
22844963Sjb				rval = EINVAL;
22944963Sjb			} else {
23053812Salfred				/* Reset the timeout and interrupted flags: */
23171581Sdeischen				curthread->timeout = 0;
23271581Sdeischen				curthread->interrupted = 0;
23313546Sjulian
23440974Sdt				/*
23544963Sjb				 * Queue the running thread for the condition
23644963Sjb				 * variable:
23740974Sdt				 */
23871581Sdeischen				cond_queue_enq(*cond, curthread);
23913546Sjulian
24044963Sjb				/* Wait forever: */
24171581Sdeischen				curthread->wakeup_time.tv_sec = -1;
24244963Sjb
24344963Sjb				/* Unlock the mutex: */
244139023Sdeischen				if (mutex_locked &&
245113658Sdeischen				    ((rval = _mutex_cv_unlock(mutex)) != 0)) {
24644963Sjb					/*
24744963Sjb					 * Cannot unlock the mutex, so remove
24844963Sjb					 * the running thread from the condition
24944963Sjb					 * variable queue:
25044963Sjb					 */
25171581Sdeischen					cond_queue_remove(*cond, curthread);
252113658Sdeischen				}
253113658Sdeischen				else {
254139023Sdeischen					/* Remember the mutex: */
255139023Sdeischen					(*cond)->c_mutex = *mutex;
256139023Sdeischen
25744963Sjb					/*
258113658Sdeischen					 * Don't unlock the mutex the next
259113658Sdeischen					 * time through the loop (if the
260113658Sdeischen					 * thread has to be requeued after
261113658Sdeischen					 * handling a signal).
26244963Sjb					 */
263139023Sdeischen					mutex_locked = 0;
26444963Sjb
265113658Sdeischen					/*
266113658Sdeischen					 * This thread is active and is in a
267113658Sdeischen					 * critical region (holding the cv
268113658Sdeischen					 * lock); we should be able to safely
269113658Sdeischen					 * set the state.
270113658Sdeischen					 */
271115080Sdeischen					THR_SCHED_LOCK(curthread, curthread);
272113658Sdeischen					THR_SET_STATE(curthread, PS_COND_WAIT);
27356277Sjasone
274113658Sdeischen					/* Remember the CV: */
275113658Sdeischen					curthread->data.cond = *cond;
276139023Sdeischen					curthread->sigbackout = cond_wait_backout;
277115080Sdeischen					THR_SCHED_UNLOCK(curthread, curthread);
27881918Sjasone
279113658Sdeischen					/* Unlock the CV structure: */
280113658Sdeischen					THR_LOCK_RELEASE(curthread,
281113658Sdeischen					    &(*cond)->c_lock);
282113658Sdeischen
283113658Sdeischen					/* Schedule the next thread: */
284113658Sdeischen					_thr_sched_switch(curthread);
285113658Sdeischen
28681918Sjasone					/*
287113658Sdeischen					 * XXX - This really isn't a good check
288113658Sdeischen					 * since there can be more than one
289113658Sdeischen					 * thread waiting on the CV.  Signals
290113658Sdeischen					 * sent to threads waiting on mutexes
291113658Sdeischen					 * or CVs should really be deferred
292113658Sdeischen					 * until the threads are no longer
293113658Sdeischen					 * waiting, but POSIX says that signals
294113658Sdeischen					 * should be sent "as soon as possible".
29581918Sjasone					 */
296113658Sdeischen					done = (seqno != (*cond)->c_seqno);
297139023Sdeischen					if (done && !THR_IN_CONDQ(curthread)) {
29856277Sjasone						/*
299139023Sdeischen						 * The thread is dequeued, so
300139023Sdeischen						 * it is safe to clear these.
30153812Salfred						 */
302139023Sdeischen						curthread->data.cond = NULL;
303139023Sdeischen						curthread->sigbackout = NULL;
304139023Sdeischen						check_continuation(curthread,
305139023Sdeischen						    NULL, mutex);
306139023Sdeischen						return (_mutex_cv_lock(mutex));
307139023Sdeischen					}
30853812Salfred
309139023Sdeischen					/* Relock the CV structure: */
310139023Sdeischen					THR_LOCK_ACQUIRE(curthread,
311139023Sdeischen					    &(*cond)->c_lock);
312139023Sdeischen
313139023Sdeischen					/*
314139023Sdeischen					 * Clear these after taking the lock to
315139023Sdeischen					 * prevent a race condition where a
316139023Sdeischen					 * signal can arrive before dequeueing
317139023Sdeischen					 * the thread.
318139023Sdeischen					 */
319139023Sdeischen					curthread->data.cond = NULL;
320139023Sdeischen					curthread->sigbackout = NULL;
321139023Sdeischen					done = (seqno != (*cond)->c_seqno);
322139023Sdeischen
323139023Sdeischen					if (THR_IN_CONDQ(curthread)) {
32453812Salfred						cond_queue_remove(*cond,
32571581Sdeischen						    curthread);
32653812Salfred
32753812Salfred						/* Check for no more waiters: */
328157700Sdelphij						if (TAILQ_EMPTY(&(*cond)->c_queue))
32953812Salfred							(*cond)->c_mutex = NULL;
330113658Sdeischen					}
33144963Sjb				}
33240974Sdt			}
33317706Sjulian			break;
33413546Sjulian
33524827Sjb		/* Trap invalid condition variable types: */
33617706Sjulian		default:
33717706Sjulian			/* Return an invalid argument error: */
33831402Salex			rval = EINVAL;
33917706Sjulian			break;
34017706Sjulian		}
34153812Salfred
342139023Sdeischen		check_continuation(curthread, *cond,
343139023Sdeischen		    mutex_locked ? NULL : mutex);
34468516Sdeischen	} while ((done == 0) && (rval == 0));
34513546Sjulian
346139023Sdeischen	/* Unlock the condition variable structure: */
347139023Sdeischen	THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
348139023Sdeischen
349139023Sdeischen	if (mutex_locked == 0)
350139023Sdeischen		_mutex_cv_lock(mutex);
351139023Sdeischen
35213546Sjulian	/* Return the completion status: */
35313546Sjulian	return (rval);
35413546Sjulian}
35513546Sjulian
356115399Skan__strong_reference(_pthread_cond_wait, _thr_cond_wait);
357115399Skan
35813546Sjulianint
359113658Sdeischen__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
360113658Sdeischen{
361113658Sdeischen	struct pthread *curthread = _get_curthread();
362113658Sdeischen	int ret;
363113658Sdeischen
364123312Sdavidxu	_thr_cancel_enter(curthread);
365113658Sdeischen	ret = _pthread_cond_wait(cond, mutex);
366123312Sdavidxu	_thr_cancel_leave(curthread, 1);
367113658Sdeischen	return (ret);
368113658Sdeischen}
369113658Sdeischen
370113658Sdeischenint
37171581Sdeischen_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
37213546Sjulian		       const struct timespec * abstime)
37313546Sjulian{
37471581Sdeischen	struct pthread	*curthread = _get_curthread();
37556277Sjasone	int	rval = 0;
37668516Sdeischen	int	done = 0;
377139023Sdeischen	int	mutex_locked = 1;
37868516Sdeischen	int	seqno;
37913546Sjulian
380113870Sdeischen	THR_ASSERT(curthread->locklevel == 0,
381113870Sdeischen	    "cv_timedwait: locklevel is not zero!");
382113658Sdeischen
38363355Sjasone	if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
384115173Sdeischen	    abstime->tv_nsec >= 1000000000)
38568516Sdeischen		return (EINVAL);
38635027Sjb	/*
38763355Sjasone	 * If the condition variable is statically initialized, perform dynamic
38863355Sjasone	 * initialization.
38935027Sjb	 */
390174112Sdeischen	if (*cond == NULL && (rval = _pthread_cond_init(cond, NULL)) != 0)
39168516Sdeischen		return (rval);
39268516Sdeischen
393115278Sdeischen	if (!_kse_isthreaded())
394115278Sdeischen		_kse_setthreaded(1);
395115278Sdeischen
39668516Sdeischen	/*
39768516Sdeischen	 * Enter a loop waiting for a condition signal or broadcast
39868516Sdeischen	 * to wake up this thread.  A loop is needed in case the waiting
39968516Sdeischen	 * thread is interrupted by a signal to execute a signal handler.
40068516Sdeischen	 * It is not (currently) possible to remain in the waiting queue
40168516Sdeischen	 * while running a handler.  Instead, the thread is interrupted
40268516Sdeischen	 * and backed out of the waiting queue prior to executing the
40368516Sdeischen	 * signal handler.
40468516Sdeischen	 */
405139023Sdeischen
406139023Sdeischen	/* Lock the condition variable structure: */
407139023Sdeischen	THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
408139023Sdeischen	seqno = (*cond)->c_seqno;
40968516Sdeischen	do {
41047424Sjb		/*
41147424Sjb		 * If the condvar was statically allocated, properly
41247424Sjb		 * initialize the tail queue.
41347424Sjb		 */
41447424Sjb		if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) {
41547424Sjb			TAILQ_INIT(&(*cond)->c_queue);
41647424Sjb			(*cond)->c_flags |= COND_FLAGS_INITED;
41747424Sjb		}
41847424Sjb
41917706Sjulian		/* Process according to condition variable type: */
42017706Sjulian		switch ((*cond)->c_type) {
42124827Sjb		/* Fast condition variable: */
42217706Sjulian		case COND_TYPE_FAST:
42344963Sjb			if ((mutex == NULL) || (((*cond)->c_mutex != NULL) &&
42444963Sjb			    ((*cond)->c_mutex != *mutex))) {
42544963Sjb				/* Return invalid argument error: */
42644963Sjb				rval = EINVAL;
42744963Sjb			} else {
42853812Salfred				/* Reset the timeout and interrupted flags: */
42971581Sdeischen				curthread->timeout = 0;
43071581Sdeischen				curthread->interrupted = 0;
43113546Sjulian
43217706Sjulian				/*
43344963Sjb				 * Queue the running thread for the condition
43444963Sjb				 * variable:
43517706Sjulian				 */
43671581Sdeischen				cond_queue_enq(*cond, curthread);
43740974Sdt
43844963Sjb				/* Unlock the mutex: */
439139023Sdeischen				if (mutex_locked &&
440113658Sdeischen				   ((rval = _mutex_cv_unlock(mutex)) != 0)) {
44144963Sjb					/*
442113658Sdeischen					 * Cannot unlock the mutex; remove the
443113658Sdeischen					 * running thread from the condition
44444963Sjb					 * variable queue:
44544963Sjb					 */
44671581Sdeischen					cond_queue_remove(*cond, curthread);
447139023Sdeischen				} else {
448139023Sdeischen					/* Remember the mutex: */
449139023Sdeischen					(*cond)->c_mutex = *mutex;
45044963Sjb
45144963Sjb					/*
452113658Sdeischen					 * Don't unlock the mutex the next
453113658Sdeischen					 * time through the loop (if the
454113658Sdeischen					 * thread has to be requeued after
455113658Sdeischen					 * handling a signal).
45644963Sjb					 */
457139023Sdeischen					mutex_locked = 0;
45844963Sjb
459113658Sdeischen					/*
460113658Sdeischen					 * This thread is active and is in a
461113658Sdeischen					 * critical region (holding the cv
462113658Sdeischen					 * lock); we should be able to safely
463113658Sdeischen					 * set the state.
464113658Sdeischen					 */
465115080Sdeischen					THR_SCHED_LOCK(curthread, curthread);
466155962Sdeischen					/* Set the wakeup time: */
467155962Sdeischen					curthread->wakeup_time.tv_sec =
468155962Sdeischen					    abstime->tv_sec;
469155962Sdeischen					curthread->wakeup_time.tv_nsec =
470155962Sdeischen					    abstime->tv_nsec;
471113658Sdeischen					THR_SET_STATE(curthread, PS_COND_WAIT);
47268516Sdeischen
473113658Sdeischen					/* Remember the CV: */
474113658Sdeischen					curthread->data.cond = *cond;
475139023Sdeischen					curthread->sigbackout = cond_wait_backout;
476115080Sdeischen					THR_SCHED_UNLOCK(curthread, curthread);
47781918Sjasone
478113658Sdeischen					/* Unlock the CV structure: */
479113658Sdeischen					THR_LOCK_RELEASE(curthread,
480113658Sdeischen					    &(*cond)->c_lock);
481113658Sdeischen
482113658Sdeischen					/* Schedule the next thread: */
483113658Sdeischen					_thr_sched_switch(curthread);
484113658Sdeischen
48553812Salfred					/*
486113658Sdeischen					 * XXX - This really isn't a good check
487113658Sdeischen					 * since there can be more than one
488113658Sdeischen					 * thread waiting on the CV.  Signals
489113658Sdeischen					 * sent to threads waiting on mutexes
490113658Sdeischen					 * or CVs should really be deferred
491113658Sdeischen					 * until the threads are no longer
492113658Sdeischen					 * waiting, but POSIX says that signals
493113658Sdeischen					 * should be sent "as soon as possible".
49453812Salfred					 */
495113658Sdeischen					done = (seqno != (*cond)->c_seqno);
496139023Sdeischen					if (done && !THR_IN_CONDQ(curthread)) {
49781918Sjasone						/*
498139023Sdeischen						 * The thread is dequeued, so
499139023Sdeischen						 * it is safe to clear these.
50081918Sjasone						 */
501139023Sdeischen						curthread->data.cond = NULL;
502139023Sdeischen						curthread->sigbackout = NULL;
503139023Sdeischen						check_continuation(curthread,
504139023Sdeischen						    NULL, mutex);
505139023Sdeischen						return (_mutex_cv_lock(mutex));
506139023Sdeischen					}
50744963Sjb
508139023Sdeischen					/* Relock the CV structure: */
509139023Sdeischen					THR_LOCK_ACQUIRE(curthread,
510139023Sdeischen					    &(*cond)->c_lock);
511139023Sdeischen
512139023Sdeischen					/*
513139023Sdeischen					 * Clear these after taking the lock to
514139023Sdeischen					 * prevent a race condition where a
515139023Sdeischen					 * signal can arrive before dequeueing
516139023Sdeischen					 * the thread.
517139023Sdeischen					 */
518139023Sdeischen					curthread->data.cond = NULL;
519139023Sdeischen					curthread->sigbackout = NULL;
520139023Sdeischen
521139023Sdeischen					done = (seqno != (*cond)->c_seqno);
522139023Sdeischen
523139023Sdeischen					if (THR_IN_CONDQ(curthread)) {
52444963Sjb						cond_queue_remove(*cond,
52571581Sdeischen						    curthread);
52644963Sjb
52744963Sjb						/* Check for no more waiters: */
528157700Sdelphij						if (TAILQ_EMPTY(&(*cond)->c_queue))
52944963Sjb							(*cond)->c_mutex = NULL;
530113658Sdeischen					}
53144963Sjb
532113658Sdeischen					if (curthread->timeout != 0) {
533113658Sdeischen						/* The wait timedout. */
534113658Sdeischen						rval = ETIMEDOUT;
535117165Sdavidxu					}
53617706Sjulian				}
53713546Sjulian			}
53817706Sjulian			break;
53917706Sjulian
54024827Sjb		/* Trap invalid condition variable types: */
54117706Sjulian		default:
54217706Sjulian			/* Return an invalid argument error: */
54331402Salex			rval = EINVAL;
54417706Sjulian			break;
54513546Sjulian		}
54613546Sjulian
547139023Sdeischen		check_continuation(curthread, *cond,
548139023Sdeischen		    mutex_locked ? NULL : mutex);
54968516Sdeischen	} while ((done == 0) && (rval == 0));
55013546Sjulian
551139023Sdeischen	/* Unlock the condition variable structure: */
552139023Sdeischen	THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
553139023Sdeischen
554139023Sdeischen	if (mutex_locked == 0)
555139023Sdeischen		_mutex_cv_lock(mutex);
556139023Sdeischen
55713546Sjulian	/* Return the completion status: */
55813546Sjulian	return (rval);
55913546Sjulian}
56013546Sjulian
56113546Sjulianint
562113658Sdeischen__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
563113658Sdeischen		       const struct timespec *abstime)
564113658Sdeischen{
565113658Sdeischen	struct pthread *curthread = _get_curthread();
566113658Sdeischen	int ret;
567113658Sdeischen
568123312Sdavidxu	_thr_cancel_enter(curthread);
569113658Sdeischen	ret = _pthread_cond_timedwait(cond, mutex, abstime);
570123312Sdavidxu	_thr_cancel_leave(curthread, 1);
571113658Sdeischen	return (ret);
572113658Sdeischen}
573113658Sdeischen
574113658Sdeischen
575113658Sdeischenint
57671581Sdeischen_pthread_cond_signal(pthread_cond_t * cond)
57713546Sjulian{
578113658Sdeischen	struct pthread	*curthread = _get_curthread();
579113658Sdeischen	struct pthread	*pthread;
580117907Sdeischen	struct kse_mailbox *kmbx;
581113658Sdeischen	int		rval = 0;
58213546Sjulian
583113870Sdeischen	THR_ASSERT(curthread->locklevel == 0,
584113870Sdeischen	    "cv_timedwait: locklevel is not zero!");
58563355Sjasone	if (cond == NULL)
58631402Salex		rval = EINVAL;
58763355Sjasone       /*
58863355Sjasone        * If the condition variable is statically initialized, perform dynamic
58963355Sjasone        * initialization.
59063355Sjasone        */
591174112Sdeischen	else if (*cond != NULL || (rval = _pthread_cond_init(cond, NULL)) == 0) {
59235509Sjb		/* Lock the condition variable structure: */
593113658Sdeischen		THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
59413546Sjulian
59517706Sjulian		/* Process according to condition variable type: */
59617706Sjulian		switch ((*cond)->c_type) {
59724827Sjb		/* Fast condition variable: */
59817706Sjulian		case COND_TYPE_FAST:
59968516Sdeischen			/* Increment the sequence number: */
60068516Sdeischen			(*cond)->c_seqno++;
60168516Sdeischen
602113658Sdeischen			/*
603113658Sdeischen			 * Wakeups have to be done with the CV lock held;
604113658Sdeischen			 * otherwise there is a race condition where the
605113658Sdeischen			 * thread can timeout, run on another KSE, and enter
606113658Sdeischen			 * another blocking state (including blocking on a CV).
607113658Sdeischen			 */
608113658Sdeischen			if ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
609113658Sdeischen			    != NULL) {
610113658Sdeischen				THR_SCHED_LOCK(curthread, pthread);
611113658Sdeischen				cond_queue_remove(*cond, pthread);
612139023Sdeischen				pthread->sigbackout = NULL;
613117714Sdeischen				if ((pthread->kseg == curthread->kseg) &&
614117714Sdeischen				    (pthread->active_priority >
615117714Sdeischen				    curthread->active_priority))
616117714Sdeischen					curthread->critical_yield = 1;
617117907Sdeischen				kmbx = _thr_setrunnable_unlocked(pthread);
618113658Sdeischen				THR_SCHED_UNLOCK(curthread, pthread);
619117907Sdeischen				if (kmbx != NULL)
620117907Sdeischen					kse_wakeup(kmbx);
62161681Sjasone			}
62244963Sjb			/* Check for no more waiters: */
623157700Sdelphij			if (TAILQ_EMPTY(&(*cond)->c_queue))
62444963Sjb				(*cond)->c_mutex = NULL;
62517706Sjulian			break;
62617706Sjulian
62724827Sjb		/* Trap invalid condition variable types: */
62817706Sjulian		default:
62917706Sjulian			/* Return an invalid argument error: */
63031402Salex			rval = EINVAL;
63117706Sjulian			break;
63213546Sjulian		}
63313546Sjulian
63435509Sjb		/* Unlock the condition variable structure: */
635113658Sdeischen		THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
63613546Sjulian	}
63713546Sjulian
63813546Sjulian	/* Return the completion status: */
63913546Sjulian	return (rval);
64013546Sjulian}
64113546Sjulian
642115399Skan__strong_reference(_pthread_cond_signal, _thr_cond_signal);
643115399Skan
64413546Sjulianint
64571581Sdeischen_pthread_cond_broadcast(pthread_cond_t * cond)
64613546Sjulian{
647113658Sdeischen	struct pthread	*curthread = _get_curthread();
648113658Sdeischen	struct pthread	*pthread;
649117907Sdeischen	struct kse_mailbox *kmbx;
650113658Sdeischen	int		rval = 0;
65113546Sjulian
652113870Sdeischen	THR_ASSERT(curthread->locklevel == 0,
653113870Sdeischen	    "cv_timedwait: locklevel is not zero!");
65463355Sjasone	if (cond == NULL)
65535509Sjb		rval = EINVAL;
65663355Sjasone       /*
65763355Sjasone        * If the condition variable is statically initialized, perform dynamic
65863355Sjasone        * initialization.
65963355Sjasone        */
660174112Sdeischen	else if (*cond != NULL || (rval = _pthread_cond_init(cond, NULL)) == 0) {
66135509Sjb		/* Lock the condition variable structure: */
662113658Sdeischen		THR_LOCK_ACQUIRE(curthread, &(*cond)->c_lock);
66313546Sjulian
66435509Sjb		/* Process according to condition variable type: */
66535509Sjb		switch ((*cond)->c_type) {
66635509Sjb		/* Fast condition variable: */
66735509Sjb		case COND_TYPE_FAST:
66868516Sdeischen			/* Increment the sequence number: */
66968516Sdeischen			(*cond)->c_seqno++;
67068516Sdeischen
67135509Sjb			/*
67235509Sjb			 * Enter a loop to bring all threads off the
67335509Sjb			 * condition queue:
67435509Sjb			 */
675113658Sdeischen			while ((pthread = TAILQ_FIRST(&(*cond)->c_queue))
676113658Sdeischen			    != NULL) {
677113658Sdeischen				THR_SCHED_LOCK(curthread, pthread);
678113658Sdeischen				cond_queue_remove(*cond, pthread);
679139023Sdeischen				pthread->sigbackout = NULL;
680117714Sdeischen				if ((pthread->kseg == curthread->kseg) &&
681117714Sdeischen				    (pthread->active_priority >
682117714Sdeischen				    curthread->active_priority))
683117714Sdeischen					curthread->critical_yield = 1;
684117907Sdeischen				kmbx = _thr_setrunnable_unlocked(pthread);
685113658Sdeischen				THR_SCHED_UNLOCK(curthread, pthread);
686117907Sdeischen				if (kmbx != NULL)
687117907Sdeischen					kse_wakeup(kmbx);
68835509Sjb			}
68944963Sjb
69044963Sjb			/* There are no more waiting threads: */
69144963Sjb			(*cond)->c_mutex = NULL;
69235509Sjb			break;
693115399Skan
69435509Sjb		/* Trap invalid condition variable types: */
69535509Sjb		default:
69635509Sjb			/* Return an invalid argument error: */
69735509Sjb			rval = EINVAL;
69835509Sjb			break;
69913546Sjulian		}
70013546Sjulian
70135509Sjb		/* Unlock the condition variable structure: */
702113658Sdeischen		THR_LOCK_RELEASE(curthread, &(*cond)->c_lock);
70313546Sjulian	}
70413546Sjulian
70513546Sjulian	/* Return the completion status: */
70613546Sjulian	return (rval);
70713546Sjulian}
70844963Sjb
709115399Skan__strong_reference(_pthread_cond_broadcast, _thr_cond_broadcast);
710115399Skan
711139023Sdeischenstatic inline void
712139023Sdeischencheck_continuation(struct pthread *curthread, struct pthread_cond *cond,
713139023Sdeischen    pthread_mutex_t *mutex)
71467097Sdeischen{
715139023Sdeischen	if ((curthread->interrupted != 0) &&
716139023Sdeischen	    (curthread->continuation != NULL)) {
717139023Sdeischen		if (cond != NULL)
718139023Sdeischen			/* Unlock the condition variable structure: */
719139023Sdeischen			THR_LOCK_RELEASE(curthread, &cond->c_lock);
720139023Sdeischen		/*
721139023Sdeischen		 * Note that even though this thread may have been
722139023Sdeischen		 * canceled, POSIX requires that the mutex be
723139023Sdeischen		 * reaquired prior to cancellation.
724139023Sdeischen		 */
725139023Sdeischen		if (mutex != NULL)
726139023Sdeischen			_mutex_cv_lock(mutex);
727139023Sdeischen		curthread->continuation((void *) curthread);
728139023Sdeischen		PANIC("continuation returned in pthread_cond_wait.\n");
729139023Sdeischen	}
730139023Sdeischen}
731139023Sdeischen
732139023Sdeischenstatic void
733139023Sdeischencond_wait_backout(void *arg)
734139023Sdeischen{
735139023Sdeischen	struct pthread *curthread = (struct pthread *)arg;
73667097Sdeischen	pthread_cond_t	cond;
73767097Sdeischen
738113658Sdeischen	cond = curthread->data.cond;
73967097Sdeischen	if (cond != NULL) {
74067097Sdeischen		/* Lock the condition variable structure: */
741113658Sdeischen		THR_LOCK_ACQUIRE(curthread, &cond->c_lock);
74267097Sdeischen
74367097Sdeischen		/* Process according to condition variable type: */
74467097Sdeischen		switch (cond->c_type) {
74567097Sdeischen		/* Fast condition variable: */
74667097Sdeischen		case COND_TYPE_FAST:
747113658Sdeischen			cond_queue_remove(cond, curthread);
74867097Sdeischen
74967097Sdeischen			/* Check for no more waiters: */
750157700Sdelphij			if (TAILQ_EMPTY(&cond->c_queue))
75167097Sdeischen				cond->c_mutex = NULL;
75267097Sdeischen			break;
75367097Sdeischen
75467097Sdeischen		default:
75567097Sdeischen			break;
75667097Sdeischen		}
75767097Sdeischen
75867097Sdeischen		/* Unlock the condition variable structure: */
759113658Sdeischen		THR_LOCK_RELEASE(curthread, &cond->c_lock);
76067097Sdeischen	}
761139023Sdeischen	/* No need to call this again. */
762139023Sdeischen	curthread->sigbackout = NULL;
76367097Sdeischen}
76467097Sdeischen
76544963Sjb/*
76644963Sjb * Dequeue a waiting thread from the head of a condition queue in
76744963Sjb * descending priority order.
76844963Sjb */
769113658Sdeischenstatic inline struct pthread *
77044963Sjbcond_queue_deq(pthread_cond_t cond)
77144963Sjb{
772113658Sdeischen	struct pthread	*pthread;
77344963Sjb
77453812Salfred	while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) {
77567097Sdeischen		TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
776117165Sdavidxu		THR_CONDQ_CLEAR(pthread);
77753812Salfred		if ((pthread->timeout == 0) && (pthread->interrupted == 0))
77853812Salfred			/*
77953812Salfred			 * Only exit the loop when we find a thread
78053812Salfred			 * that hasn't timed out or been canceled;
78153812Salfred			 * those threads are already running and don't
78253812Salfred			 * need their run state changed.
78353812Salfred			 */
78453812Salfred			break;
78544963Sjb	}
78644963Sjb
787113658Sdeischen	return (pthread);
78844963Sjb}
78944963Sjb
79044963Sjb/*
79144963Sjb * Remove a waiting thread from a condition queue in descending priority
79244963Sjb * order.
79344963Sjb */
79444963Sjbstatic inline void
795113658Sdeischencond_queue_remove(pthread_cond_t cond, struct pthread *pthread)
79644963Sjb{
79744963Sjb	/*
79844963Sjb	 * Because pthread_cond_timedwait() can timeout as well
79944963Sjb	 * as be signaled by another thread, it is necessary to
80044963Sjb	 * guard against removing the thread from the queue if
80144963Sjb	 * it isn't in the queue.
80244963Sjb	 */
803113658Sdeischen	if (THR_IN_CONDQ(pthread)) {
80467097Sdeischen		TAILQ_REMOVE(&cond->c_queue, pthread, sqe);
805113658Sdeischen		THR_CONDQ_CLEAR(pthread);
80644963Sjb	}
80744963Sjb}
80844963Sjb
80944963Sjb/*
81044963Sjb * Enqueue a waiting thread to a condition queue in descending priority
81144963Sjb * order.
81244963Sjb */
81344963Sjbstatic inline void
814113658Sdeischencond_queue_enq(pthread_cond_t cond, struct pthread *pthread)
81544963Sjb{
816113658Sdeischen	struct pthread *tid = TAILQ_LAST(&cond->c_queue, cond_head);
81744963Sjb
818113658Sdeischen	THR_ASSERT(!THR_IN_SYNCQ(pthread),
819113658Sdeischen	    "cond_queue_enq: thread already queued!");
82067097Sdeischen
82144963Sjb	/*
82244963Sjb	 * For the common case of all threads having equal priority,
82344963Sjb	 * we perform a quick check against the priority of the thread
82444963Sjb	 * at the tail of the queue.
82544963Sjb	 */
82644963Sjb	if ((tid == NULL) || (pthread->active_priority <= tid->active_priority))
82767097Sdeischen		TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe);
82844963Sjb	else {
82944963Sjb		tid = TAILQ_FIRST(&cond->c_queue);
83044963Sjb		while (pthread->active_priority <= tid->active_priority)
83167097Sdeischen			tid = TAILQ_NEXT(tid, sqe);
83267097Sdeischen		TAILQ_INSERT_BEFORE(tid, pthread, sqe);
83344963Sjb	}
834113658Sdeischen	THR_CONDQ_SET(pthread);
83567097Sdeischen	pthread->data.cond = cond;
83644963Sjb}
837