Fix mdoc(7)/man(7) mix up.
[netbsd-mini2440.git] / lib / libpthread / pthread_cond.c
blob817e563c4d93e485a5936bd8914471be8f903180
1 /* $NetBSD: pthread_cond.c,v 1.53 2008/10/25 14:14:11 yamt Exp $ */
3 /*-
4 * Copyright (c) 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Nathan J. Williams and Andrew Doran.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * We assume that there will be no contention on pthread_cond_t::ptc_lock
34 * because functioning applications must call both the wait and wakeup
35 * functions while holding the same application provided mutex. The
36 * spinlock is present only to prevent libpthread causing the application
37 * to crash or malfunction as a result of corrupted data structures, in
38 * the event that the application is buggy.
40 * If there is contention on spinlock when real-time threads are in use,
41 * it could cause a deadlock due to priority inversion: the thread holding
42 * the spinlock may not get CPU time to make forward progress and release
43 * the spinlock to a higher priority thread that is waiting for it.
44 * Contention on the spinlock will only occur with buggy applications,
45 * so at the time of writing it's not considered a major bug in libpthread.
48 #include <sys/cdefs.h>
49 __RCSID("$NetBSD: pthread_cond.c,v 1.53 2008/10/25 14:14:11 yamt Exp $");
51 #include <errno.h>
52 #include <sys/time.h>
53 #include <sys/types.h>
55 #include "pthread.h"
56 #include "pthread_int.h"
58 int _sys_nanosleep(const struct timespec *, struct timespec *);
60 extern int pthread__started;
62 static int pthread_cond_wait_nothread(pthread_t, pthread_mutex_t *,
63 const struct timespec *);
65 int _pthread_cond_has_waiters_np(pthread_cond_t *);
67 __weak_alias(pthread_cond_has_waiters_np,_pthread_cond_has_waiters_np)
69 __strong_alias(__libc_cond_init,pthread_cond_init)
70 __strong_alias(__libc_cond_signal,pthread_cond_signal)
71 __strong_alias(__libc_cond_broadcast,pthread_cond_broadcast)
72 __strong_alias(__libc_cond_wait,pthread_cond_wait)
73 __strong_alias(__libc_cond_timedwait,pthread_cond_timedwait)
74 __strong_alias(__libc_cond_destroy,pthread_cond_destroy)
76 int
77 pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
80 pthread__error(EINVAL, "Invalid condition variable attribute",
81 (attr == NULL) || (attr->ptca_magic == _PT_CONDATTR_MAGIC));
83 cond->ptc_magic = _PT_COND_MAGIC;
84 pthread_lockinit(&cond->ptc_lock);
85 PTQ_INIT(&cond->ptc_waiters);
86 cond->ptc_mutex = NULL;
88 return 0;
92 int
93 pthread_cond_destroy(pthread_cond_t *cond)
96 pthread__error(EINVAL, "Invalid condition variable",
97 cond->ptc_magic == _PT_COND_MAGIC);
98 pthread__error(EBUSY, "Destroying condition variable in use",
99 cond->ptc_mutex == NULL);
101 cond->ptc_magic = _PT_COND_DEAD;
103 return 0;
106 inline int
107 pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
108 const struct timespec *abstime)
110 pthread_t self;
111 int retval;
113 pthread__error(EINVAL, "Invalid condition variable",
114 cond->ptc_magic == _PT_COND_MAGIC);
115 pthread__error(EINVAL, "Invalid mutex",
116 mutex->ptm_magic == _PT_MUTEX_MAGIC);
117 pthread__error(EPERM, "Mutex not locked in condition wait",
118 mutex->ptm_owner != NULL);
119 if (abstime != NULL) {
120 pthread__error(EINVAL, "Invalid wait time",
121 (abstime->tv_sec >= 0) &&
122 (abstime->tv_nsec >= 0) &&
123 (abstime->tv_nsec < 1000000000));
126 self = pthread__self();
128 /* Just hang out for a while if threads aren't running yet. */
129 if (__predict_false(pthread__started == 0)) {
130 return pthread_cond_wait_nothread(self, mutex, abstime);
132 if (__predict_false(self->pt_cancel)) {
133 pthread__cancelled();
136 /* Note this thread as waiting on the CV. */
137 pthread__spinlock(self, &cond->ptc_lock);
138 cond->ptc_mutex = mutex;
139 PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep);
140 self->pt_sleepobj = cond;
141 pthread__spinunlock(self, &cond->ptc_lock);
143 do {
144 self->pt_willpark = 1;
145 pthread_mutex_unlock(mutex);
146 self->pt_willpark = 0;
147 self->pt_blocking++;
148 retval = _lwp_park(abstime, self->pt_unpark,
149 __UNVOLATILE(&mutex->ptm_waiters),
150 __UNVOLATILE(&mutex->ptm_waiters));
151 self->pt_unpark = 0;
152 self->pt_blocking--;
153 membar_sync();
154 pthread_mutex_lock(mutex);
157 * If we have cancelled then exit. POSIX dictates that
158 * the mutex must be held when we action the cancellation.
160 * If we absorbed a pthread_cond_signal() and cannot take
161 * the wakeup, we must ensure that another thread does.
163 * If awoke early, we may still be on the sleep queue and
164 * must remove ourself.
166 if (__predict_false(retval != 0)) {
167 switch (errno) {
168 case EINTR:
169 case EALREADY:
170 retval = 0;
171 break;
172 default:
173 retval = errno;
174 break;
177 if (__predict_false(self->pt_cancel | retval)) {
178 pthread_cond_signal(cond);
179 if (self->pt_cancel) {
180 pthread__cancelled();
182 break;
184 } while (self->pt_sleepobj != NULL);
186 return retval;
190 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
193 return pthread_cond_timedwait(cond, mutex, NULL);
196 static int __noinline
197 pthread__cond_wake_one(pthread_cond_t *cond)
199 pthread_t self, signaled;
200 pthread_mutex_t *mutex;
201 lwpid_t lid;
203 pthread__error(EINVAL, "Invalid condition variable",
204 cond->ptc_magic == _PT_COND_MAGIC);
207 * Pull the first thread off the queue. If the current thread
208 * is associated with the condition variable, remove it without
209 * awakening (error case in pthread_cond_timedwait()).
211 self = pthread__self();
212 pthread__spinlock(self, &cond->ptc_lock);
213 if (self->pt_sleepobj == cond) {
214 PTQ_REMOVE(&cond->ptc_waiters, self, pt_sleep);
215 self->pt_sleepobj = NULL;
217 signaled = PTQ_FIRST(&cond->ptc_waiters);
218 if (__predict_false(signaled == NULL)) {
219 cond->ptc_mutex = NULL;
220 pthread__spinunlock(self, &cond->ptc_lock);
221 return 0;
223 mutex = cond->ptc_mutex;
224 if (PTQ_NEXT(signaled, pt_sleep) == NULL) {
225 cond->ptc_mutex = NULL;
226 PTQ_INIT(&cond->ptc_waiters);
227 } else {
228 PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
230 signaled->pt_sleepobj = NULL;
231 lid = signaled->pt_lid;
232 pthread__spinunlock(self, &cond->ptc_lock);
235 * For all valid uses of pthread_cond_signal(), the caller will
236 * hold the mutex that the target is using to synchronize with.
237 * To avoid the target awakening and immediatley blocking on the
238 * mutex, transfer the thread to be awoken to the current thread's
239 * deferred wakeup list. The waiter will be set running when the
240 * caller (this thread) releases the mutex.
242 if (__predict_false(self->pt_nwaiters == (size_t)pthread__unpark_max)) {
243 (void)_lwp_unpark_all(self->pt_waiters, self->pt_nwaiters,
244 __UNVOLATILE(&mutex->ptm_waiters));
245 self->pt_nwaiters = 0;
247 self->pt_waiters[self->pt_nwaiters++] = lid;
248 pthread__mutex_deferwake(self, mutex);
249 return 0;
253 pthread_cond_signal(pthread_cond_t *cond)
256 if (__predict_true(PTQ_EMPTY(&cond->ptc_waiters)))
257 return 0;
258 return pthread__cond_wake_one(cond);
261 static int __noinline
262 pthread__cond_wake_all(pthread_cond_t *cond)
264 pthread_t self, signaled;
265 pthread_mutex_t *mutex;
266 u_int max;
267 size_t nwaiters;
269 pthread__error(EINVAL, "Invalid condition variable",
270 cond->ptc_magic == _PT_COND_MAGIC);
273 * Try to defer waking threads (see pthread_cond_signal()).
274 * Only transfer waiters for which there is no pending wakeup.
276 self = pthread__self();
277 pthread__spinlock(self, &cond->ptc_lock);
278 max = pthread__unpark_max;
279 mutex = cond->ptc_mutex;
280 nwaiters = self->pt_nwaiters;
281 PTQ_FOREACH(signaled, &cond->ptc_waiters, pt_sleep) {
282 if (__predict_false(nwaiters == max)) {
283 /* Overflow. */
284 (void)_lwp_unpark_all(self->pt_waiters,
285 nwaiters, __UNVOLATILE(&mutex->ptm_waiters));
286 nwaiters = 0;
288 signaled->pt_sleepobj = NULL;
289 self->pt_waiters[nwaiters++] = signaled->pt_lid;
291 PTQ_INIT(&cond->ptc_waiters);
292 self->pt_nwaiters = nwaiters;
293 cond->ptc_mutex = NULL;
294 pthread__spinunlock(self, &cond->ptc_lock);
295 pthread__mutex_deferwake(self, mutex);
297 return 0;
301 pthread_cond_broadcast(pthread_cond_t *cond)
304 if (__predict_true(PTQ_EMPTY(&cond->ptc_waiters)))
305 return 0;
306 return pthread__cond_wake_all(cond);
310 _pthread_cond_has_waiters_np(pthread_cond_t *cond)
313 return !PTQ_EMPTY(&cond->ptc_waiters);
317 pthread_condattr_init(pthread_condattr_t *attr)
320 attr->ptca_magic = _PT_CONDATTR_MAGIC;
322 return 0;
326 pthread_condattr_destroy(pthread_condattr_t *attr)
329 pthread__error(EINVAL, "Invalid condition variable attribute",
330 attr->ptca_magic == _PT_CONDATTR_MAGIC);
332 attr->ptca_magic = _PT_CONDATTR_DEAD;
334 return 0;
337 /* Utility routine to hang out for a while if threads haven't started yet. */
338 static int
339 pthread_cond_wait_nothread(pthread_t self, pthread_mutex_t *mutex,
340 const struct timespec *abstime)
342 struct timespec now, diff;
343 int retval;
345 if (abstime == NULL) {
346 diff.tv_sec = 99999999;
347 diff.tv_nsec = 0;
348 } else {
349 clock_gettime(CLOCK_REALTIME, &now);
350 if (timespeccmp(abstime, &now, <))
351 timespecclear(&diff);
352 else
353 timespecsub(abstime, &now, &diff);
356 do {
357 pthread__testcancel(self);
358 pthread_mutex_unlock(mutex);
359 retval = _sys_nanosleep(&diff, NULL);
360 pthread_mutex_lock(mutex);
361 } while (abstime == NULL && retval == 0);
362 pthread__testcancel(self);
364 if (retval == 0)
365 return ETIMEDOUT;
366 else
367 /* spurious wakeup */
368 return 0;