pthread_cond.c revision 1.34.2.2 1 /* $NetBSD: pthread_cond.c,v 1.34.2.2 2008/01/09 01:36:34 matt Exp $ */
2
3 /*-
4 * Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Nathan J. Williams and Andrew Doran.
9 *
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include <sys/cdefs.h>
40 __RCSID("$NetBSD: pthread_cond.c,v 1.34.2.2 2008/01/09 01:36:34 matt Exp $");
41
42 #include <errno.h>
43 #include <sys/time.h>
44 #include <sys/types.h>
45
46 #include "pthread.h"
47 #include "pthread_int.h"
48
49 int _sys_nanosleep(const struct timespec *, struct timespec *);
50
51 extern int pthread__started;
52
53 static int pthread_cond_wait_nothread(pthread_t, pthread_mutex_t *,
54 const struct timespec *);
55
56 __strong_alias(__libc_cond_init,pthread_cond_init)
57 __strong_alias(__libc_cond_signal,pthread_cond_signal)
58 __strong_alias(__libc_cond_broadcast,pthread_cond_broadcast)
59 __strong_alias(__libc_cond_wait,pthread_cond_wait)
60 __strong_alias(__libc_cond_timedwait,pthread_cond_timedwait)
61 __strong_alias(__libc_cond_destroy,pthread_cond_destroy)
62
63 int
64 pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
65 {
66
67 pthread__error(EINVAL, "Invalid condition variable attribute",
68 (attr == NULL) || (attr->ptca_magic == _PT_CONDATTR_MAGIC));
69
70 cond->ptc_magic = _PT_COND_MAGIC;
71 pthread_lockinit(&cond->ptc_lock);
72 PTQ_INIT(&cond->ptc_waiters);
73 cond->ptc_mutex = NULL;
74
75 return 0;
76 }
77
78
79 int
80 pthread_cond_destroy(pthread_cond_t *cond)
81 {
82
83 pthread__error(EINVAL, "Invalid condition variable",
84 cond->ptc_magic == _PT_COND_MAGIC);
85 pthread__error(EBUSY, "Destroying condition variable in use",
86 cond->ptc_mutex == NULL);
87
88 cond->ptc_magic = _PT_COND_DEAD;
89
90 return 0;
91 }
92
93
94 int
95 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
96 {
97 pthread_t self;
98
99 pthread__error(EINVAL, "Invalid condition variable",
100 cond->ptc_magic == _PT_COND_MAGIC);
101 pthread__error(EINVAL, "Invalid mutex",
102 mutex->ptm_magic == _PT_MUTEX_MAGIC);
103 pthread__error(EPERM, "Mutex not locked in condition wait",
104 mutex->ptm_owner != NULL);
105
106 self = pthread__self();
107
108 /* Just hang out for a while if threads aren't running yet. */
109 if (__predict_false(pthread__started == 0))
110 return pthread_cond_wait_nothread(self, mutex, NULL);
111
112 if (__predict_false(self->pt_cancel))
113 pthread__cancelled();
114
115 /*
116 * Note this thread as waiting on the CV. To ensure good
117 * performance it's critical that the spinlock is held for
118 * as short a time as possible - that means no system calls.
119 */
120 pthread__spinlock(self, &cond->ptc_lock);
121 #ifdef ERRORCHECK
122 if (cond->ptc_mutex == NULL)
123 cond->ptc_mutex = mutex;
124 else {
125 pthread__error(EINVAL,
126 "Multiple mutexes used for condition wait",
127 cond->ptc_mutex == mutex);
128 }
129 #else
130 cond->ptc_mutex = mutex;
131 #endif
132 PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep);
133 self->pt_signalled = 0;
134 self->pt_sleeponq = 1;
135 self->pt_sleepobj = &cond->ptc_waiters;
136 pthread__spinunlock(self, &cond->ptc_lock);
137
138 /*
139 * Before releasing the mutex, note that this thread is
140 * about to block by setting the willpark flag. If there
141 * is a single waiter on the mutex, setting the flag will
142 * defer restarting it until calling into the kernel to
143 * park, saving a syscall & involuntary context switch.
144 */
145 self->pt_willpark = 1;
146 pthread_mutex_unlock(mutex);
147 (void)pthread__park(self, &cond->ptc_lock, &cond->ptc_waiters,
148 NULL, 1, &mutex->ptm_blocked);
149 pthread_mutex_lock(mutex);
150
151 /*
152 * If we awoke abnormally the waiters list will have been
153 * made empty by the current thread (in pthread__park()),
154 * so we can check the value safely without locking.
155 *
156 * Otherwise, it will have been updated by whichever thread
157 * last issued a wakeup.
158 */
159 if (PTQ_EMPTY(&cond->ptc_waiters) && cond->ptc_mutex != NULL) {
160 pthread__spinlock(self, &cond->ptc_lock);
161 if (PTQ_EMPTY(&cond->ptc_waiters))
162 cond->ptc_mutex = NULL;
163 pthread__spinunlock(self, &cond->ptc_lock);
164 }
165
166 /*
167 * If we have cancelled then exit. POSIX dictates that the
168 * mutex must be held when we action the cancellation.
169 */
170 if (__predict_false(self->pt_cancel)) {
171 if (self->pt_signalled)
172 pthread_cond_signal(cond);
173 pthread__cancelled();
174 }
175
176 return 0;
177 }
178
179 int
180 pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
181 const struct timespec *abstime)
182 {
183 pthread_t self;
184 int retval;
185
186 pthread__error(EINVAL, "Invalid condition variable",
187 cond->ptc_magic == _PT_COND_MAGIC);
188 pthread__error(EINVAL, "Invalid mutex",
189 mutex->ptm_magic == _PT_MUTEX_MAGIC);
190 pthread__error(EPERM, "Mutex not locked in condition wait",
191 mutex->ptm_owner != NULL);
192 pthread__error(EINVAL, "Invalid wait time",
193 (abstime->tv_sec >= 0) &&
194 (abstime->tv_nsec >= 0) && (abstime->tv_nsec < 1000000000));
195
196 self = pthread__self();
197
198 /* Just hang out for a while if threads aren't running yet. */
199 if (__predict_false(pthread__started == 0))
200 return pthread_cond_wait_nothread(self, mutex, abstime);
201
202 if (__predict_false(self->pt_cancel))
203 pthread__cancelled();
204
205 /*
206 * Note this thread as waiting on the CV. To ensure good
207 * performance it's critical that the spinlock is held for
208 * as short a time as possible - that means no system calls.
209 */
210 pthread__spinlock(self, &cond->ptc_lock);
211 #ifdef ERRORCHECK
212 if (cond->ptc_mutex == NULL)
213 cond->ptc_mutex = mutex;
214 else {
215 pthread__error(EINVAL,
216 "Multiple mutexes used for condition wait",
217 cond->ptc_mutex == mutex);
218 }
219 #else
220 cond->ptc_mutex = mutex;
221 #endif
222 PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep);
223 self->pt_signalled = 0;
224 self->pt_sleeponq = 1;
225 self->pt_sleepobj = &cond->ptc_waiters;
226 pthread__spinunlock(self, &cond->ptc_lock);
227
228 /*
229 * Before releasing the mutex, note that this thread is
230 * about to block by setting the willpark flag. If there
231 * is a single waiter on the mutex, setting the flag will
232 * defer restarting it until calling into the kernel to
233 * park, saving a syscall & involuntary context switch.
234 */
235 self->pt_willpark = 1;
236 pthread_mutex_unlock(mutex);
237 retval = pthread__park(self, &cond->ptc_lock, &cond->ptc_waiters,
238 abstime, 1, &mutex->ptm_blocked);
239 pthread_mutex_lock(mutex);
240
241 /*
242 * If we awoke abnormally the waiters list will have been
243 * made empty by the current thread (in pthread__park()),
244 * so we can check the value safely without locking.
245 *
246 * Otherwise, it will have been updated by whichever thread
247 * last issued a wakeup.
248 */
249 if (PTQ_EMPTY(&cond->ptc_waiters) && cond->ptc_mutex != NULL) {
250 pthread__spinlock(self, &cond->ptc_lock);
251 if (PTQ_EMPTY(&cond->ptc_waiters))
252 cond->ptc_mutex = NULL;
253 pthread__spinunlock(self, &cond->ptc_lock);
254 }
255
256 /*
257 * If we have cancelled then exit. POSIX dictates that the
258 * mutex must be held when we action the cancellation.
259 */
260 if (__predict_false(self->pt_cancel | retval)) {
261 if (self->pt_signalled)
262 pthread_cond_signal(cond);
263 if (self->pt_cancel)
264 pthread__cancelled();
265 }
266
267 return retval;
268 }
269
270 int
271 pthread_cond_signal(pthread_cond_t *cond)
272 {
273 pthread_t self, signaled;
274 pthread_mutex_t *mutex;
275
276 pthread__error(EINVAL, "Invalid condition variable",
277 cond->ptc_magic == _PT_COND_MAGIC);
278
279 if (PTQ_EMPTY(&cond->ptc_waiters))
280 return 0;
281
282 self = pthread__self();
283 pthread__spinlock(self, &cond->ptc_lock);
284
285 /*
286 * Find a thread that is still blocked (no pending wakeup).
287 * A wakeup can be pending if we have interrupted unpark_all
288 * as it releases the interlock.
289 */
290 PTQ_FOREACH(signaled, &cond->ptc_waiters, pt_sleep) {
291 if (signaled->pt_sleepobj != NULL)
292 break;
293 }
294 if (__predict_false(signaled == NULL)) {
295 cond->ptc_mutex = NULL;
296 pthread__spinunlock(self, &cond->ptc_lock);
297 return 0;
298 }
299
300 /*
301 * Pull the thread off the queue, and set pt_signalled.
302 *
303 * After resuming execution, the thread must check to see if it
304 * has been restarted as a result of pthread_cond_signal(). If it
305 * has, but cannot take the wakeup (because of eg a timeout) then
306 * try to ensure that another thread sees it. This is necessary
307 * because there may be multiple waiters, and at least one should
308 * take the wakeup if possible.
309 */
310 PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
311 mutex = cond->ptc_mutex;
312 if (PTQ_EMPTY(&cond->ptc_waiters))
313 cond->ptc_mutex = NULL;
314 signaled->pt_signalled = 1;
315
316 /*
317 * For all valid uses of pthread_cond_signal(), the caller will
318 * hold the mutex that the target is using to synchronize with.
319 * To avoid the target awakening and immediatley blocking on the
320 * mutex, transfer the thread to be awoken to the current thread's
321 * deferred wakeup list. The waiter will be set running when the
322 * caller (this thread) releases the mutex.
323 */
324 if (mutex != NULL && self->pt_nwaiters < pthread__unpark_max &&
325 pthread__mutex_deferwake(self, mutex)) {
326 signaled->pt_sleepobj = NULL;
327 signaled->pt_sleeponq = 0;
328 pthread__spinunlock(self, &cond->ptc_lock);
329 self->pt_waiters[self->pt_nwaiters++] = signaled->pt_lid;
330 } else {
331 pthread__unpark(self, &cond->ptc_lock,
332 &cond->ptc_waiters, signaled);
333 }
334
335 return 0;
336 }
337
338
339 int
340 pthread_cond_broadcast(pthread_cond_t *cond)
341 {
342 pthread_t self, signaled, next;
343 pthread_mutex_t *mutex;
344
345 pthread__error(EINVAL, "Invalid condition variable",
346 cond->ptc_magic == _PT_COND_MAGIC);
347
348 if (PTQ_EMPTY(&cond->ptc_waiters))
349 return 0;
350
351 self = pthread__self();
352 pthread__spinlock(self, &cond->ptc_lock);
353 mutex = cond->ptc_mutex;
354 cond->ptc_mutex = NULL;
355
356 /*
357 * Try to defer waking threads (see pthread_cond_signal()).
358 * Only transfer waiters for which there is no pending wakeup.
359 */
360 if (mutex != NULL && pthread__mutex_deferwake(self, mutex)) {
361 for (signaled = PTQ_FIRST(&cond->ptc_waiters);
362 signaled != NULL;
363 signaled = next) {
364 next = PTQ_NEXT(signaled, pt_sleep);
365 if (__predict_false(signaled->pt_sleepobj == NULL))
366 continue;
367 if (self->pt_nwaiters == pthread__unpark_max) {
368 /* Overflow, take the slow path. */
369 break;
370 }
371 PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
372 signaled->pt_sleepobj = NULL;
373 signaled->pt_sleeponq = 0;
374 self->pt_waiters[self->pt_nwaiters++] =
375 signaled->pt_lid;
376 }
377 if (signaled == NULL) {
378 /* Anything more to do? */
379 pthread__spinunlock(self, &cond->ptc_lock);
380 return 0;
381 }
382 }
383 pthread__unpark_all(self, &cond->ptc_lock, &cond->ptc_waiters);
384 return 0;
385 }
386
387
388 int
389 pthread_condattr_init(pthread_condattr_t *attr)
390 {
391
392 attr->ptca_magic = _PT_CONDATTR_MAGIC;
393
394 return 0;
395 }
396
397
398 int
399 pthread_condattr_destroy(pthread_condattr_t *attr)
400 {
401
402 pthread__error(EINVAL, "Invalid condition variable attribute",
403 attr->ptca_magic == _PT_CONDATTR_MAGIC);
404
405 attr->ptca_magic = _PT_CONDATTR_DEAD;
406
407 return 0;
408 }
409
410 /* Utility routine to hang out for a while if threads haven't started yet. */
411 static int
412 pthread_cond_wait_nothread(pthread_t self, pthread_mutex_t *mutex,
413 const struct timespec *abstime)
414 {
415 struct timespec now, diff;
416 int retval;
417
418 if (abstime == NULL) {
419 diff.tv_sec = 99999999;
420 diff.tv_nsec = 0;
421 } else {
422 clock_gettime(CLOCK_REALTIME, &now);
423 if (timespeccmp(abstime, &now, <))
424 timespecclear(&diff);
425 else
426 timespecsub(abstime, &now, &diff);
427 }
428
429 do {
430 pthread__testcancel(self);
431 pthread_mutex_unlock(mutex);
432 retval = _sys_nanosleep(&diff, NULL);
433 pthread_mutex_lock(mutex);
434 } while (abstime == NULL && retval == 0);
435 pthread__testcancel(self);
436
437 if (retval == 0)
438 return ETIMEDOUT;
439 else
440 /* spurious wakeup */
441 return 0;
442 }
443