thr_cond.c revision 165110
1100966Siwasaki/*
2100966Siwasaki * Copyright (c) 2005 David Xu <davidxu@freebsd.org>
3100966Siwasaki * All rights reserved.
4100966Siwasaki *
5167802Sjkim * Redistribution and use in source and binary forms, with or without
6100966Siwasaki * modification, are permitted provided that the following conditions
7100966Siwasaki * are met:
8100966Siwasaki * 1. Redistributions of source code must retain the above copyright
9100966Siwasaki *    notice unmodified, this list of conditions, and the following
10100966Siwasaki *    disclaimer.
11100966Siwasaki * 2. Redistributions in binary form must reproduce the above copyright
12100966Siwasaki *    notice, this list of conditions and the following disclaimer in the
13167802Sjkim *    documentation and/or other materials provided with the distribution.
14100966Siwasaki *
15100966Siwasaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16100966Siwasaki * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17100966Siwasaki * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18100966Siwasaki * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19100966Siwasaki * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20100966Siwasaki * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21100966Siwasaki * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22100966Siwasaki * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23100966Siwasaki * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24100966Siwasaki * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25100966Siwasaki *
26100966Siwasaki * $FreeBSD: head/lib/libthr/thread/thr_cond.c 165110 2006-12-12 03:08:49Z davidxu $
27100966Siwasaki */
28100966Siwasaki
29100966Siwasaki#include "namespace.h"
30100966Siwasaki#include <stdlib.h>
31100966Siwasaki#include <errno.h>
32100966Siwasaki#include <string.h>
33100966Siwasaki#include <pthread.h>
34100966Siwasaki#include <limits.h>
35100966Siwasaki#include "un-namespace.h"
36100966Siwasaki
37100966Siwasaki#include "thr_private.h"
38100966Siwasaki
39100966Siwasaki/*
40100966Siwasaki * Prototypes
41100966Siwasaki */
42100966Siwasakiint	__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
43100966Siwasakiint	__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
44100966Siwasaki		       const struct timespec * abstime);
45100966Siwasakistatic int cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
46100966Siwasakistatic int cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
47100966Siwasaki		    const struct timespec *abstime, int cancel);
48100966Siwasakistatic int cond_signal_common(pthread_cond_t *cond, int broadcast);
49100966Siwasaki
50100966Siwasaki/*
51100966Siwasaki * Double underscore versions are cancellation points.  Single underscore
52100966Siwasaki * versions are not and are provided for libc internal usage (which
53100966Siwasaki * shouldn't introduce cancellation points).
54100966Siwasaki */
55100966Siwasaki__weak_reference(__pthread_cond_wait, pthread_cond_wait);
56100966Siwasaki__weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait);
57100966Siwasaki
58100966Siwasaki__weak_reference(_pthread_cond_init, pthread_cond_init);
59100966Siwasaki__weak_reference(_pthread_cond_destroy, pthread_cond_destroy);
60100966Siwasaki__weak_reference(_pthread_cond_signal, pthread_cond_signal);
61100966Siwasaki__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast);
62100966Siwasaki
63100966Siwasakistatic int
64100966Siwasakicond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
65100966Siwasaki{
66100966Siwasaki	pthread_cond_t	pcond;
67100966Siwasaki	int             rval = 0;
68100966Siwasaki
69100966Siwasaki	if ((pcond = (pthread_cond_t)
70100966Siwasaki	    calloc(1, sizeof(struct pthread_cond))) == NULL) {
71100966Siwasaki		rval = ENOMEM;
72100966Siwasaki	} else {
73100966Siwasaki		/*
74100966Siwasaki		 * Initialise the condition variable structure:
75100966Siwasaki		 */
76100966Siwasaki		if (cond_attr == NULL || *cond_attr == NULL) {
77100966Siwasaki			pcond->c_pshared = 0;
78100966Siwasaki			pcond->c_clockid = CLOCK_REALTIME;
79100966Siwasaki		} else {
80100966Siwasaki			pcond->c_pshared = (*cond_attr)->c_pshared;
81100966Siwasaki			pcond->c_clockid = (*cond_attr)->c_clockid;
82100966Siwasaki		}
83100966Siwasaki		_thr_umutex_init(&pcond->c_lock);
84100966Siwasaki		*cond = pcond;
85100966Siwasaki	}
86100966Siwasaki	/* Return the completion status: */
87100966Siwasaki	return (rval);
88100966Siwasaki}
89100966Siwasaki
90100966Siwasakistatic int
91100966Siwasakiinit_static(struct pthread *thread, pthread_cond_t *cond)
92100966Siwasaki{
93100966Siwasaki	int ret;
94100966Siwasaki
95100966Siwasaki	THR_LOCK_ACQUIRE(thread, &_cond_static_lock);
96100966Siwasaki
97100966Siwasaki	if (*cond == NULL)
98100966Siwasaki		ret = cond_init(cond, NULL);
99100966Siwasaki	else
100100966Siwasaki		ret = 0;
101100966Siwasaki
102100966Siwasaki	THR_LOCK_RELEASE(thread, &_cond_static_lock);
103100966Siwasaki
104100966Siwasaki	return (ret);
105100966Siwasaki}
106100966Siwasaki
107100966Siwasakiint
108100966Siwasaki_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
109100966Siwasaki{
110100966Siwasaki
111100966Siwasaki	*cond = NULL;
112100966Siwasaki	return (cond_init(cond, cond_attr));
113100966Siwasaki}
114100966Siwasaki
115100966Siwasakiint
116100966Siwasaki_pthread_cond_destroy(pthread_cond_t *cond)
117100966Siwasaki{
118100966Siwasaki	struct pthread		*curthread = _get_curthread();
119100966Siwasaki	struct pthread_cond	*cv;
120100966Siwasaki	int			rval = 0;
121151600Sobrien
122151600Sobrien	if (*cond == NULL)
123151600Sobrien		rval = EINVAL;
124100966Siwasaki	else {
125100966Siwasaki		cv = *cond;
126100966Siwasaki		THR_UMUTEX_LOCK(curthread, &cv->c_lock);
127100966Siwasaki		/*
128100966Siwasaki		 * NULL the caller's pointer now that the condition
129100966Siwasaki		 * variable has been destroyed:
130100966Siwasaki		 */
131100966Siwasaki		*cond = NULL;
132100966Siwasaki		THR_UMUTEX_UNLOCK(curthread, &cv->c_lock);
133100966Siwasaki
134100966Siwasaki		/*
135151937Sjkim		 * Free the memory allocated for the condition
136151937Sjkim		 * variable structure:
137100966Siwasaki		 */
138100966Siwasaki		free(cv);
139151937Sjkim	}
140100966Siwasaki	/* Return the completion status: */
141100966Siwasaki	return (rval);
142100966Siwasaki}
143100966Siwasaki
144100966Siwasakistruct cond_cancel_info
145100966Siwasaki{
146100966Siwasaki	pthread_mutex_t	*mutex;
147100966Siwasaki	pthread_cond_t	*cond;
148100966Siwasaki	int		count;
149100966Siwasaki};
150100966Siwasaki
151100966Siwasakistatic void
152100966Siwasakicond_cancel_handler(void *arg)
153100966Siwasaki{
154100966Siwasaki	struct pthread *curthread = _get_curthread();
155100966Siwasaki	struct cond_cancel_info *info = (struct cond_cancel_info *)arg;
156100966Siwasaki	pthread_cond_t  cv;
157100966Siwasaki
158100966Siwasaki	if (info->cond != NULL) {
159100966Siwasaki		cv = *(info->cond);
160100966Siwasaki		THR_UMUTEX_UNLOCK(curthread, &cv->c_lock);
161100966Siwasaki	}
162100966Siwasaki	_mutex_cv_lock(info->mutex, info->count);
163167802Sjkim}
164100966Siwasaki
165100966Siwasakistatic int
166100966Siwasakicond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
167100966Siwasaki	const struct timespec *abstime, int cancel)
168100966Siwasaki{
169100966Siwasaki	struct pthread	*curthread = _get_curthread();
170100966Siwasaki	struct timespec ts, ts2, *tsp;
171100966Siwasaki	struct cond_cancel_info info;
172100966Siwasaki	pthread_cond_t  cv;
173100966Siwasaki	int		ret = 0;
174100966Siwasaki
175100966Siwasaki	/*
176100966Siwasaki	 * If the condition variable is statically initialized,
177100966Siwasaki	 * perform the dynamic initialization:
178100966Siwasaki	 */
179100966Siwasaki	if (__predict_false(*cond == NULL &&
180100966Siwasaki	    (ret = init_static(curthread, cond)) != 0))
181100966Siwasaki		return (ret);
182100966Siwasaki
183100966Siwasaki	cv = *cond;
184100966Siwasaki	THR_UMUTEX_LOCK(curthread, &cv->c_lock);
185100966Siwasaki	ret = _mutex_cv_unlock(mutex, &info.count);
186100966Siwasaki	if (ret) {
187100966Siwasaki		THR_UMUTEX_UNLOCK(curthread, &cv->c_lock);
188100966Siwasaki		return (ret);
189100966Siwasaki	}
190100966Siwasaki
191100966Siwasaki	info.mutex = mutex;
192100966Siwasaki	info.cond  = cond;
193100966Siwasaki
194100966Siwasaki	if (abstime != NULL) {
195100966Siwasaki		clock_gettime(cv->c_clockid, &ts);
196100966Siwasaki		TIMESPEC_SUB(&ts2, abstime, &ts);
197167802Sjkim		tsp = &ts2;
198100966Siwasaki	} else
199100966Siwasaki		tsp = NULL;
200100966Siwasaki
201100966Siwasaki	if (cancel) {
202100966Siwasaki		THR_CLEANUP_PUSH(curthread, cond_cancel_handler, &info);
203100966Siwasaki		_thr_cancel_enter_defer(curthread);
204100966Siwasaki		ret = _thr_ucond_wait(&cv->c_kerncv, &cv->c_lock, tsp, 1);
205100966Siwasaki		info.cond = NULL;
206100966Siwasaki		_thr_cancel_leave_defer(curthread, ret);
207100966Siwasaki		THR_CLEANUP_POP(curthread, 0);
208100966Siwasaki	} else {
209100966Siwasaki		ret = _thr_ucond_wait(&cv->c_kerncv, &cv->c_lock, tsp, 0);
210167802Sjkim	}
211167802Sjkim	if (ret == EINTR)
212100966Siwasaki		ret = 0;
213100966Siwasaki	_mutex_cv_lock(mutex, info.count);
214100966Siwasaki	return (ret);
215100966Siwasaki}
216100966Siwasaki
217100966Siwasakiint
218100966Siwasaki_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
219100966Siwasaki{
220100966Siwasaki
221100966Siwasaki	return (cond_wait_common(cond, mutex, NULL, 0));
222100966Siwasaki}
223100966Siwasaki
224100966Siwasakiint
225100966Siwasaki__pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
226100966Siwasaki{
227167802Sjkim
228100966Siwasaki	return (cond_wait_common(cond, mutex, NULL, 1));
229167802Sjkim}
230100966Siwasaki
231100966Siwasakiint
232100966Siwasaki_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
233100966Siwasaki		       const struct timespec * abstime)
234100966Siwasaki{
235128212Snjl
236128212Snjl	if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
237100966Siwasaki	    abstime->tv_nsec >= 1000000000)
238100966Siwasaki		return (EINVAL);
239128212Snjl
240100966Siwasaki	return (cond_wait_common(cond, mutex, abstime, 0));
241100966Siwasaki}
242100966Siwasaki
243100966Siwasakiint
244100966Siwasaki__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
245100966Siwasaki		       const struct timespec *abstime)
246100966Siwasaki{
247100966Siwasaki
248100966Siwasaki	if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
249100966Siwasaki	    abstime->tv_nsec >= 1000000000)
250100966Siwasaki		return (EINVAL);
251100966Siwasaki
252100966Siwasaki	return (cond_wait_common(cond, mutex, abstime, 1));
253100966Siwasaki}
254100966Siwasaki
255100966Siwasakistatic int
256100966Siwasakicond_signal_common(pthread_cond_t *cond, int broadcast)
257100966Siwasaki{
258167802Sjkim	struct pthread	*curthread = _get_curthread();
259100966Siwasaki	pthread_cond_t	cv;
260100966Siwasaki	int		ret = 0;
261100966Siwasaki
262100966Siwasaki	/*
263167802Sjkim	 * If the condition variable is statically initialized, perform dynamic
264100966Siwasaki	 * initialization.
265100966Siwasaki	 */
266167802Sjkim	if (__predict_false(*cond == NULL &&
267129684Snjl	    (ret = init_static(curthread, cond)) != 0))
268167802Sjkim		return (ret);
269167802Sjkim
270167802Sjkim	cv = *cond;
271167802Sjkim	THR_UMUTEX_LOCK(curthread, &cv->c_lock);
272167802Sjkim	if (!broadcast)
273167802Sjkim		ret = _thr_ucond_signal(&cv->c_kerncv);
274167802Sjkim	else
275167802Sjkim		ret = _thr_ucond_broadcast(&cv->c_kerncv);
276167802Sjkim	THR_UMUTEX_UNLOCK(curthread, &cv->c_lock);
277167802Sjkim	return (ret);
278167802Sjkim}
279167802Sjkim
280167802Sjkimint
281167802Sjkim_pthread_cond_signal(pthread_cond_t * cond)
282167802Sjkim{
283167802Sjkim
284167802Sjkim	return (cond_signal_common(cond, 0));
285167802Sjkim}
286100966Siwasaki
287167802Sjkimint
288167802Sjkim_pthread_cond_broadcast(pthread_cond_t * cond)
289100966Siwasaki{
290100966Siwasaki
291100966Siwasaki	return (cond_signal_common(cond, 1));
292100966Siwasaki}
293100966Siwasaki