thr_cond.c revision 22315
1/*
2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by John Birrell.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33#include <stdlib.h>
34#include <errno.h>
35#ifdef _THREAD_SAFE
36#include <pthread.h>
37#include "pthread_private.h"
38
39int
40pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
41{
42	enum pthread_cond_type type;
43	pthread_cond_t	pcond;
44	int             rval = 0;
45
46	if (cond == NULL) {
47		errno = EINVAL;
48		rval = -1;
49	} else {
50		/*
51		 * Check if a pointer to a condition variable attribute structure was
52		 * passed by the caller:
53		 */
54		if (cond_attr != NULL && *cond_attr != NULL) {
55			/* Default to a fast condition variable: */
56			type = (*cond_attr)->c_type;
57		} else {
58			/* Default to a fast condition variable: */
59			type = COND_TYPE_FAST;
60		}
61
62		/* Process according to condition variable type: */
63		switch (type) {
64			/* Fast condition variable: */
65		case COND_TYPE_FAST:
66			/* Nothing to do here. */
67			break;
68
69			/* Trap invalid condition variable types: */
70		default:
71			/* Return an invalid argument error: */
72			errno = EINVAL;
73			rval = -1;
74			break;
75		}
76
77		/* Check for no errors: */
78		if (rval == 0) {
79			if ((pcond = (pthread_cond_t) malloc(sizeof(struct pthread_cond))) == NULL) {
80				errno = ENOMEM;
81				rval = -1;
82			} else {
83				/*
84				 * Initialise the condition variable
85				 * structure:
86				 */
87				_thread_queue_init(&pcond->c_queue);
88				pcond->c_flags |= COND_FLAGS_INITED;
89				pcond->c_type = type;
90				*cond = pcond;
91			}
92		}
93	}
94	/* Return the completion status: */
95	return (rval);
96}
97
98int
99pthread_cond_destroy(pthread_cond_t * cond)
100{
101	int             rval = 0;
102
103	if (cond == NULL || *cond == NULL) {
104		errno = EINVAL;
105		rval = -1;
106	} else {
107		/* Process according to condition variable type: */
108		switch ((*cond)->c_type) {
109			/* Fast condition variable: */
110		case COND_TYPE_FAST:
111			/* Nothing to do here. */
112			break;
113
114			/* Trap invalid condition variable types: */
115		default:
116			/* Return an invalid argument error: */
117			errno = EINVAL;
118			rval = -1;
119			break;
120		}
121
122		/* Check for errors: */
123		if (rval == 0) {
124			/* Destroy the contents of the condition structure: */
125			_thread_queue_init(&(*cond)->c_queue);
126			(*cond)->c_flags = 0;
127			free(*cond);
128			*cond = NULL;
129		}
130	}
131	/* Return the completion status: */
132	return (rval);
133}
134
135int
136pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
137{
138	int             rval = 0;
139	int             status;
140
141	if (cond == NULL || *cond == NULL) {
142		errno = EINVAL;
143		rval = -1;
144	} else {
145		/* Block signals: */
146		_thread_kern_sig_block(&status);
147
148		/* Process according to condition variable type: */
149		switch ((*cond)->c_type) {
150			/* Fast condition variable: */
151		case COND_TYPE_FAST:
152			/* Queue the running thread for the condition variable: */
153				_thread_queue_enq(&(*cond)->c_queue, _thread_run);
154
155			/* Unlock the mutex: */
156			pthread_mutex_unlock(mutex);
157
158			/* Schedule the next thread: */
159			_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__);
160
161			/* Block signals: */
162			_thread_kern_sig_block(NULL);
163
164			/* Lock the mutex: */
165			rval = pthread_mutex_lock(mutex);
166			break;
167
168			/* Trap invalid condition variable types: */
169		default:
170			/* Return an invalid argument error: */
171			errno = EINVAL;
172			rval = -1;
173			break;
174		}
175
176		/* Unblock signals: */
177		_thread_kern_sig_unblock(status);
178	}
179
180	/* Return the completion status: */
181	return (rval);
182}
183
184int
185pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
186		       const struct timespec * abstime)
187{
188	int             rval = 0;
189	int             status;
190
191	if (cond == NULL || *cond == NULL) {
192		errno = EINVAL;
193		rval = -1;
194	} else {
195		/* Block signals: */
196		_thread_kern_sig_block(&status);
197
198		/* Process according to condition variable type: */
199		switch ((*cond)->c_type) {
200			/* Fast condition variable: */
201		case COND_TYPE_FAST:
202			/* Set the wakeup time: */
203			_thread_run->wakeup_time.tv_sec = abstime->tv_sec;
204			_thread_run->wakeup_time.tv_nsec = abstime->tv_nsec;
205
206			/* Reset the timeout flag: */
207			_thread_run->timeout = 0;
208
209			/* Queue the running thread for the condition variable: */
210			_thread_queue_enq(&(*cond)->c_queue, _thread_run);
211
212			/* Unlock the mutex: */
213			if ((rval = pthread_mutex_unlock(mutex)) != 0) {
214				/*
215				 * Cannot unlock the mutex, so remove the running
216				 * thread from the condition variable queue:
217				 */
218				_thread_queue_deq(&(*cond)->c_queue);
219			} else {
220				/* Schedule the next thread: */
221				_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__);
222
223				/* Block signals: */
224				_thread_kern_sig_block(NULL);
225
226				/* Lock the mutex: */
227				if ((rval = pthread_mutex_lock(mutex)) != 0) {
228				}
229				/* Check if the wait timed out: */
230				else if (_thread_run->timeout) {
231					/* Return a timeout error: */
232					errno = EAGAIN;
233					rval = -1;
234				}
235			}
236			break;
237
238			/* Trap invalid condition variable types: */
239		default:
240			/* Return an invalid argument error: */
241			errno = EINVAL;
242			rval = -1;
243			break;
244		}
245
246		/* Unblock signals: */
247		_thread_kern_sig_unblock(status);
248	}
249
250	/* Return the completion status: */
251	return (rval);
252}
253
254int
255pthread_cond_signal(pthread_cond_t * cond)
256{
257	int             rval = 0;
258	int             status;
259	pthread_t       pthread;
260
261	if (cond == NULL || *cond == NULL) {
262		errno = EINVAL;
263		rval = -1;
264	} else {
265		/* Block signals: */
266		_thread_kern_sig_block(&status);
267
268		/* Process according to condition variable type: */
269		switch ((*cond)->c_type) {
270			/* Fast condition variable: */
271		case COND_TYPE_FAST:
272			/* Bring the next thread off the condition queue: */
273			if ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) {
274				/* Allow the thread to run: */
275				PTHREAD_NEW_STATE(pthread,PS_RUNNING);
276			}
277			break;
278
279			/* Trap invalid condition variable types: */
280		default:
281			/* Return an invalid argument error: */
282			errno = EINVAL;
283			rval = -1;
284			break;
285		}
286
287		/* Unblock signals: */
288		_thread_kern_sig_unblock(status);
289	}
290
291	/* Return the completion status: */
292	return (rval);
293}
294
295int
296pthread_cond_broadcast(pthread_cond_t * cond)
297{
298	int             rval = 0;
299	int             status;
300	pthread_t       pthread;
301
302	/* Block signals: */
303	_thread_kern_sig_block(&status);
304
305	/* Process according to condition variable type: */
306	switch ((*cond)->c_type) {
307		/* Fast condition variable: */
308	case COND_TYPE_FAST:
309		/* Enter a loop to bring all threads off the condition queue: */
310		while ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) {
311			/* Allow the thread to run: */
312			PTHREAD_NEW_STATE(pthread,PS_RUNNING);
313		}
314		break;
315
316		/* Trap invalid condition variable types: */
317	default:
318		/* Return an invalid argument error: */
319		errno = EINVAL;
320		rval = -1;
321		break;
322	}
323
324	/* Unblock signals: */
325	_thread_kern_sig_unblock(status);
326
327	/* Return the completion status: */
328	return (rval);
329}
330#endif
331