thr_cond.c revision 17706
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
2313546Sjulian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS 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 *
3213546Sjulian */
3313546Sjulian#include <stdlib.h>
3413546Sjulian#include <errno.h>
3513546Sjulian#ifdef _THREAD_SAFE
3613546Sjulian#include <pthread.h>
3713546Sjulian#include "pthread_private.h"
3813546Sjulian
3913546Sjulianint
4013546Sjulianpthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
4113546Sjulian{
4213546Sjulian	enum pthread_cond_type type;
4317706Sjulian	pthread_cond_t	pcond;
4413546Sjulian	int             rval = 0;
4513546Sjulian
4617706Sjulian	if (cond == NULL) {
4717706Sjulian		errno = EINVAL;
4817706Sjulian		rval = -1;
4913546Sjulian	} else {
5017706Sjulian		/*
5117706Sjulian		 * Check if a pointer to a condition variable attribute structure was
5217706Sjulian		 * passed by the caller:
5317706Sjulian		 */
5417706Sjulian		if (cond_attr != NULL && *cond_attr != NULL) {
5517706Sjulian			/* Default to a fast condition variable: */
5617706Sjulian			type = (*cond_attr)->c_type;
5717706Sjulian		} else {
5817706Sjulian			/* Default to a fast condition variable: */
5917706Sjulian			type = COND_TYPE_FAST;
6017706Sjulian		}
6113546Sjulian
6217706Sjulian		/* Process according to condition variable type: */
6317706Sjulian		switch (type) {
6417706Sjulian			/* Fast condition variable: */
6517706Sjulian		case COND_TYPE_FAST:
6617706Sjulian			/* Nothing to do here. */
6717706Sjulian			break;
6813546Sjulian
6917706Sjulian			/* Trap invalid condition variable types: */
7017706Sjulian		default:
7117706Sjulian			/* Return an invalid argument error: */
7217706Sjulian			errno = EINVAL;
7317706Sjulian			rval = -1;
7417706Sjulian			break;
7517706Sjulian		}
7613546Sjulian
7717706Sjulian		/* Check for no errors: */
7817706Sjulian		if (rval == 0) {
7917706Sjulian			if ((pcond = (pthread_cond_t) malloc(sizeof(struct pthread_cond))) == NULL) {
8017706Sjulian				errno = ENOMEM;
8117706Sjulian				rval = -1;
8217706Sjulian			} else {
8317706Sjulian				/*
8417706Sjulian				 * Initialise the condition variable
8517706Sjulian				 * structure:
8617706Sjulian				 */
8717706Sjulian				_thread_queue_init(&pcond->c_queue);
8817706Sjulian				pcond->c_flags |= COND_FLAGS_INITED;
8917706Sjulian				pcond->c_type = type;
9017706Sjulian				*cond = pcond;
9117706Sjulian			}
9217706Sjulian		}
9313546Sjulian	}
9413546Sjulian	/* Return the completion status: */
9513546Sjulian	return (rval);
9613546Sjulian}
9713546Sjulian
9813546Sjulianint
9913546Sjulianpthread_cond_destroy(pthread_cond_t * cond)
10013546Sjulian{
10113546Sjulian	int             rval = 0;
10213546Sjulian
10317706Sjulian	if (cond == NULL || *cond == NULL) {
10417706Sjulian		errno = EINVAL;
10513546Sjulian		rval = -1;
10617706Sjulian	} else {
10717706Sjulian		/* Process according to condition variable type: */
10817706Sjulian		switch ((*cond)->c_type) {
10917706Sjulian			/* Fast condition variable: */
11017706Sjulian		case COND_TYPE_FAST:
11117706Sjulian			/* Nothing to do here. */
11217706Sjulian			break;
11313546Sjulian
11417706Sjulian			/* Trap invalid condition variable types: */
11517706Sjulian		default:
11617706Sjulian			/* Return an invalid argument error: */
11717706Sjulian			errno = EINVAL;
11817706Sjulian			rval = -1;
11917706Sjulian			break;
12017706Sjulian		}
12117706Sjulian
12217706Sjulian		/* Check for errors: */
12317706Sjulian		if (rval == 0) {
12417706Sjulian			/* Destroy the contents of the condition structure: */
12517706Sjulian			_thread_queue_init(&(*cond)->c_queue);
12617706Sjulian			(*cond)->c_flags = 0;
12717706Sjulian			free(*cond);
12817706Sjulian			*cond = NULL;
12917706Sjulian		}
13013546Sjulian	}
13113546Sjulian	/* Return the completion status: */
13213546Sjulian	return (rval);
13313546Sjulian}
13413546Sjulian
13513546Sjulianint
13613546Sjulianpthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
13713546Sjulian{
13813546Sjulian	int             rval = 0;
13913546Sjulian	int             status;
14013546Sjulian
14117706Sjulian	if (cond == NULL || *cond == NULL) {
14217706Sjulian		errno = EINVAL;
14317706Sjulian		rval = -1;
14417706Sjulian	} else {
14517706Sjulian		/* Block signals: */
14617706Sjulian		_thread_kern_sig_block(&status);
14713546Sjulian
14817706Sjulian		/* Process according to condition variable type: */
14917706Sjulian		switch ((*cond)->c_type) {
15017706Sjulian			/* Fast condition variable: */
15117706Sjulian		case COND_TYPE_FAST:
15217706Sjulian			/* Queue the running thread for the condition variable: */
15317706Sjulian				_thread_queue_enq(&(*cond)->c_queue, _thread_run);
15413546Sjulian
15517706Sjulian			/* Unlock the mutex: */
15617706Sjulian			pthread_mutex_unlock(mutex);
15713546Sjulian
15817706Sjulian			/* Schedule the next thread: */
15917706Sjulian			_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__);
16013546Sjulian
16117706Sjulian			/* Block signals: */
16217706Sjulian			_thread_kern_sig_block(NULL);
16313546Sjulian
16417706Sjulian			/* Lock the mutex: */
16517706Sjulian			rval = pthread_mutex_lock(mutex);
16617706Sjulian			break;
16713546Sjulian
16817706Sjulian			/* Trap invalid condition variable types: */
16917706Sjulian		default:
17017706Sjulian			/* Return an invalid argument error: */
17117706Sjulian			errno = EINVAL;
17217706Sjulian			rval = -1;
17317706Sjulian			break;
17417706Sjulian		}
17517706Sjulian
17617706Sjulian		/* Unblock signals: */
17717706Sjulian		_thread_kern_sig_unblock(status);
17813546Sjulian	}
17913546Sjulian
18013546Sjulian	/* Return the completion status: */
18113546Sjulian	return (rval);
18213546Sjulian}
18313546Sjulian
18413546Sjulianint
18513546Sjulianpthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
18613546Sjulian		       const struct timespec * abstime)
18713546Sjulian{
18813546Sjulian	int             rval = 0;
18913546Sjulian	int             status;
19013546Sjulian
19117706Sjulian	if (cond == NULL || *cond == NULL) {
19217706Sjulian		errno = EINVAL;
19317706Sjulian		rval = -1;
19417706Sjulian	} else {
19517706Sjulian		/* Block signals: */
19617706Sjulian		_thread_kern_sig_block(&status);
19713546Sjulian
19817706Sjulian		/* Process according to condition variable type: */
19917706Sjulian		switch ((*cond)->c_type) {
20017706Sjulian			/* Fast condition variable: */
20117706Sjulian		case COND_TYPE_FAST:
20217706Sjulian			/* Set the wakeup time: */
20317706Sjulian#if	defined(__FreeBSD__)
20417706Sjulian			_thread_run->wakeup_time.ts_sec = abstime->ts_sec;
20517706Sjulian			_thread_run->wakeup_time.ts_nsec = abstime->ts_nsec;
20617706Sjulian#else
20717706Sjulian			_thread_run->wakeup_time.tv_sec = abstime->tv_sec;
20817706Sjulian			_thread_run->wakeup_time.tv_nsec = abstime->tv_nsec;
20917706Sjulian#endif
21013546Sjulian
21117706Sjulian			/* Reset the timeout flag: */
21217706Sjulian			_thread_run->timeout = 0;
21313546Sjulian
21417706Sjulian			/* Queue the running thread for the condition variable: */
21517706Sjulian			_thread_queue_enq(&(*cond)->c_queue, _thread_run);
21613546Sjulian
21717706Sjulian			/* Unlock the mutex: */
21817706Sjulian			if ((rval = pthread_mutex_unlock(mutex)) != 0) {
21917706Sjulian				/*
22017706Sjulian				 * Cannot unlock the mutex, so remove the running
22117706Sjulian				 * thread from the condition variable queue:
22217706Sjulian				 */
22317706Sjulian				_thread_queue_deq(&(*cond)->c_queue);
22417706Sjulian			} else {
22517706Sjulian				/* Schedule the next thread: */
22617706Sjulian				_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__);
22713546Sjulian
22817706Sjulian				/* Block signals: */
22917706Sjulian				_thread_kern_sig_block(NULL);
23013546Sjulian
23117706Sjulian				/* Lock the mutex: */
23217706Sjulian				if ((rval = pthread_mutex_lock(mutex)) != 0) {
23317706Sjulian				}
23417706Sjulian				/* Check if the wait timed out: */
23517706Sjulian				else if (_thread_run->timeout) {
23617706Sjulian					/* Return a timeout error: */
23717706Sjulian					errno = EAGAIN;
23817706Sjulian					rval = -1;
23917706Sjulian				}
24013546Sjulian			}
24117706Sjulian			break;
24217706Sjulian
24317706Sjulian			/* Trap invalid condition variable types: */
24417706Sjulian		default:
24517706Sjulian			/* Return an invalid argument error: */
24617706Sjulian			errno = EINVAL;
24717706Sjulian			rval = -1;
24817706Sjulian			break;
24913546Sjulian		}
25013546Sjulian
25117706Sjulian		/* Unblock signals: */
25217706Sjulian		_thread_kern_sig_unblock(status);
25313546Sjulian	}
25413546Sjulian
25513546Sjulian	/* Return the completion status: */
25613546Sjulian	return (rval);
25713546Sjulian}
25813546Sjulian
25913546Sjulianint
26013546Sjulianpthread_cond_signal(pthread_cond_t * cond)
26113546Sjulian{
26213546Sjulian	int             rval = 0;
26313546Sjulian	int             status;
26413546Sjulian	pthread_t       pthread;
26513546Sjulian
26617706Sjulian	if (cond == NULL || *cond == NULL) {
26717706Sjulian		errno = EINVAL;
26817706Sjulian		rval = -1;
26917706Sjulian	} else {
27017706Sjulian		/* Block signals: */
27117706Sjulian		_thread_kern_sig_block(&status);
27213546Sjulian
27317706Sjulian		/* Process according to condition variable type: */
27417706Sjulian		switch ((*cond)->c_type) {
27517706Sjulian			/* Fast condition variable: */
27617706Sjulian		case COND_TYPE_FAST:
27717706Sjulian			/* Bring the next thread off the condition queue: */
27817706Sjulian			if ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) {
27917706Sjulian				/* Allow the thread to run: */
28017706Sjulian				pthread->state = PS_RUNNING;
28117706Sjulian			}
28217706Sjulian			break;
28317706Sjulian
28417706Sjulian			/* Trap invalid condition variable types: */
28517706Sjulian		default:
28617706Sjulian			/* Return an invalid argument error: */
28717706Sjulian			errno = EINVAL;
28817706Sjulian			rval = -1;
28917706Sjulian			break;
29013546Sjulian		}
29113546Sjulian
29217706Sjulian		/* Unblock signals: */
29317706Sjulian		_thread_kern_sig_unblock(status);
29413546Sjulian	}
29513546Sjulian
29613546Sjulian	/* Return the completion status: */
29713546Sjulian	return (rval);
29813546Sjulian}
29913546Sjulian
30013546Sjulianint
30113546Sjulianpthread_cond_broadcast(pthread_cond_t * cond)
30213546Sjulian{
30313546Sjulian	int             rval = 0;
30413546Sjulian	int             status;
30513546Sjulian	pthread_t       pthread;
30613546Sjulian
30713546Sjulian	/* Block signals: */
30813546Sjulian	_thread_kern_sig_block(&status);
30913546Sjulian
31013546Sjulian	/* Process according to condition variable type: */
31117706Sjulian	switch ((*cond)->c_type) {
31213546Sjulian		/* Fast condition variable: */
31313546Sjulian	case COND_TYPE_FAST:
31413546Sjulian		/* Enter a loop to bring all threads off the condition queue: */
31517706Sjulian		while ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) {
31613546Sjulian			/* Allow the thread to run: */
31713546Sjulian			pthread->state = PS_RUNNING;
31813546Sjulian		}
31913546Sjulian		break;
32013546Sjulian
32113546Sjulian		/* Trap invalid condition variable types: */
32213546Sjulian	default:
32313546Sjulian		/* Return an invalid argument error: */
32417706Sjulian		errno = EINVAL;
32513546Sjulian		rval = -1;
32613546Sjulian		break;
32713546Sjulian	}
32813546Sjulian
32913546Sjulian	/* Unblock signals: */
33013546Sjulian	_thread_kern_sig_unblock(status);
33113546Sjulian
33213546Sjulian	/* Return the completion status: */
33313546Sjulian	return (rval);
33413546Sjulian}
33513546Sjulian#endif
336