pthread_cond.c revision 1.51 1 /* $NetBSD: pthread_cond.c,v 1.51 2008/07/18 16:17:11 pooka Exp $ */
2
3 /*-
4 * Copyright (c) 2001, 2006, 2007, 2008 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 *
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.
30 */
31
32 /*
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.
39 *
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.
46 */
47
48 #include <sys/cdefs.h>
49 __RCSID("$NetBSD: pthread_cond.c,v 1.51 2008/07/18 16:17:11 pooka Exp $");
50
51 #include <errno.h>
52 #include <sys/time.h>
53 #include <sys/types.h>
54
55 #include "pthread.h"
56 #include "pthread_int.h"
57
58 int _sys_nanosleep(const struct timespec *, struct timespec *);
59
60 extern int pthread__started;
61
62 static int pthread_cond_wait_nothread(pthread_t, pthread_mutex_t *,
63 const struct timespec *);
64
65 int _pthread_cond_has_waiters_np(pthread_cond_t *);
66
67 __weak_alias(pthread_cond_has_waiters_np,_pthread_cond_has_waiters_np);
68
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)
75
76 int
77 pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
78 {
79
80 pthread__error(EINVAL, "Invalid condition variable attribute",
81 (attr == NULL) || (attr->ptca_magic == _PT_CONDATTR_MAGIC));
82
83 cond->ptc_magic = _PT_COND_MAGIC;
84 pthread_lockinit(&cond->ptc_lock);
85 PTQ_INIT(&cond->ptc_waiters);
86 cond->ptc_mutex = NULL;
87
88 return 0;
89 }
90
91
92 int
93 pthread_cond_destroy(pthread_cond_t *cond)
94 {
95
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);
100
101 cond->ptc_magic = _PT_COND_DEAD;
102
103 return 0;
104 }
105
106 inline int
107 pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
108 const struct timespec *abstime)
109 {
110 pthread_t self;
111 int retval;
112
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));
124 }
125
126 self = pthread__self();
127
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);
131 }
132 if (__predict_false(self->pt_cancel)) {
133 pthread__cancelled();
134 }
135
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);
142
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);
155
156 /*
157 * If we have cancelled then exit. POSIX dictates that
158 * the mutex must be held when we action the cancellation.
159 *
160 * If we absorbed a pthread_cond_signal() and cannot take
161 * the wakeup, we must ensure that another thread does.
162 *
163 * If awoke early, we may still be on the sleep queue and
164 * must remove ourself.
165 */
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;
175 }
176 }
177 if (__predict_false(self->pt_cancel | retval)) {
178 pthread_cond_signal(cond);
179 if (self->pt_cancel) {
180 pthread__cancelled();
181 }
182 break;
183 }
184 } while (self->pt_sleepobj != NULL);
185
186 return retval;
187 }
188
189 int
190 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
191 {
192
193 return pthread_cond_timedwait(cond, mutex, NULL);
194 }
195
196 static int __noinline
197 pthread__cond_wake_one(pthread_cond_t *cond)
198 {
199 pthread_t self, signaled;
200 pthread_mutex_t *mutex;
201 lwpid_t lid;
202
203 pthread__error(EINVAL, "Invalid condition variable",
204 cond->ptc_magic == _PT_COND_MAGIC);
205
206 /*
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()).
210 */
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;
216 }
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;
222 }
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);
229 }
230 signaled->pt_sleepobj = NULL;
231 lid = signaled->pt_lid;
232 pthread__spinunlock(self, &cond->ptc_lock);
233
234 /*
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.
241 */
242 if (__predict_false(self->pt_nwaiters == pthread__unpark_max)) {
243 (void)_lwp_unpark_all(self->pt_waiters, self->pt_nwaiters,
244 __UNVOLATILE(&mutex->ptm_waiters));
245 self->pt_nwaiters = 0;
246 }
247 self->pt_waiters[self->pt_nwaiters++] = lid;
248 pthread__mutex_deferwake(self, mutex);
249 return 0;
250 }
251
252 int
253 pthread_cond_signal(pthread_cond_t *cond)
254 {
255
256 if (__predict_true(PTQ_EMPTY(&cond->ptc_waiters)))
257 return 0;
258 return pthread__cond_wake_one(cond);
259 }
260
261 static int __noinline
262 pthread__cond_wake_all(pthread_cond_t *cond)
263 {
264 pthread_t self, signaled;
265 pthread_mutex_t *mutex;
266 u_int max, nwaiters;
267
268 pthread__error(EINVAL, "Invalid condition variable",
269 cond->ptc_magic == _PT_COND_MAGIC);
270
271 /*
272 * Try to defer waking threads (see pthread_cond_signal()).
273 * Only transfer waiters for which there is no pending wakeup.
274 */
275 self = pthread__self();
276 pthread__spinlock(self, &cond->ptc_lock);
277 max = pthread__unpark_max;
278 mutex = cond->ptc_mutex;
279 nwaiters = self->pt_nwaiters;
280 PTQ_FOREACH(signaled, &cond->ptc_waiters, pt_sleep) {
281 if (__predict_false(nwaiters == max)) {
282 /* Overflow. */
283 (void)_lwp_unpark_all(self->pt_waiters,
284 nwaiters, __UNVOLATILE(&mutex->ptm_waiters));
285 nwaiters = 0;
286 }
287 signaled->pt_sleepobj = NULL;
288 self->pt_waiters[nwaiters++] = signaled->pt_lid;
289 }
290 PTQ_INIT(&cond->ptc_waiters);
291 self->pt_nwaiters = nwaiters;
292 cond->ptc_mutex = NULL;
293 pthread__spinunlock(self, &cond->ptc_lock);
294 pthread__mutex_deferwake(self, mutex);
295
296 return 0;
297 }
298
299 int
300 pthread_cond_broadcast(pthread_cond_t *cond)
301 {
302
303 if (__predict_true(PTQ_EMPTY(&cond->ptc_waiters)))
304 return 0;
305 return pthread__cond_wake_all(cond);
306 }
307
308 int
309 _pthread_cond_has_waiters_np(pthread_cond_t *cond)
310 {
311
312 return !PTQ_EMPTY(&cond->ptc_waiters);
313 }
314
315 int
316 pthread_condattr_init(pthread_condattr_t *attr)
317 {
318
319 attr->ptca_magic = _PT_CONDATTR_MAGIC;
320
321 return 0;
322 }
323
324 int
325 pthread_condattr_destroy(pthread_condattr_t *attr)
326 {
327
328 pthread__error(EINVAL, "Invalid condition variable attribute",
329 attr->ptca_magic == _PT_CONDATTR_MAGIC);
330
331 attr->ptca_magic = _PT_CONDATTR_DEAD;
332
333 return 0;
334 }
335
336 /* Utility routine to hang out for a while if threads haven't started yet. */
337 static int
338 pthread_cond_wait_nothread(pthread_t self, pthread_mutex_t *mutex,
339 const struct timespec *abstime)
340 {
341 struct timespec now, diff;
342 int retval;
343
344 if (abstime == NULL) {
345 diff.tv_sec = 99999999;
346 diff.tv_nsec = 0;
347 } else {
348 clock_gettime(CLOCK_REALTIME, &now);
349 if (timespeccmp(abstime, &now, <))
350 timespecclear(&diff);
351 else
352 timespecsub(abstime, &now, &diff);
353 }
354
355 do {
356 pthread__testcancel(self);
357 pthread_mutex_unlock(mutex);
358 retval = _sys_nanosleep(&diff, NULL);
359 pthread_mutex_lock(mutex);
360 } while (abstime == NULL && retval == 0);
361 pthread__testcancel(self);
362
363 if (retval == 0)
364 return ETIMEDOUT;
365 else
366 /* spurious wakeup */
367 return 0;
368 }
369