pthread_cond.c revision 1.57.2.1 1 /* $NetBSD: pthread_cond.c,v 1.57.2.1 2012/11/20 03:00:44 tls 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.57.2.1 2012/11/20 03:00:44 tls Exp $");
50
51 #include <errno.h>
52 #include <sys/time.h>
53 #include <sys/types.h>
54 #include <stdlib.h>
55
56 #include "pthread.h"
57 #include "pthread_int.h"
58
59 int _sys___nanosleep50(const struct timespec *, struct timespec *);
60
61 extern int pthread__started;
62
63 static int pthread_cond_wait_nothread(pthread_t, pthread_mutex_t *,
64 pthread_cond_t *, const struct timespec *);
65
66 int _pthread_cond_has_waiters_np(pthread_cond_t *);
67
68 __weak_alias(pthread_cond_has_waiters_np,_pthread_cond_has_waiters_np)
69
70 __strong_alias(__libc_cond_init,pthread_cond_init)
71 __strong_alias(__libc_cond_signal,pthread_cond_signal)
72 __strong_alias(__libc_cond_broadcast,pthread_cond_broadcast)
73 __strong_alias(__libc_cond_wait,pthread_cond_wait)
74 __strong_alias(__libc_cond_timedwait,pthread_cond_timedwait)
75 __strong_alias(__libc_cond_destroy,pthread_cond_destroy)
76
77 int
78 pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
79 {
80
81 pthread__error(EINVAL, "Invalid condition variable attribute",
82 (attr == NULL) || (attr->ptca_magic == _PT_CONDATTR_MAGIC));
83
84 cond->ptc_magic = _PT_COND_MAGIC;
85 pthread_lockinit(&cond->ptc_lock);
86 PTQ_INIT(&cond->ptc_waiters);
87 cond->ptc_mutex = NULL;
88 if (attr && attr->ptca_private) {
89 cond->ptc_private = malloc(sizeof(clockid_t));
90 if (cond->ptc_private == NULL)
91 return errno;
92 *(clockid_t *)cond->ptc_private =
93 *(clockid_t *)attr->ptca_private;
94 } else
95 cond->ptc_private = NULL;
96
97 return 0;
98 }
99
100
101 int
102 pthread_cond_destroy(pthread_cond_t *cond)
103 {
104
105 pthread__error(EINVAL, "Invalid condition variable",
106 cond->ptc_magic == _PT_COND_MAGIC);
107 pthread__error(EBUSY, "Destroying condition variable in use",
108 cond->ptc_mutex == NULL);
109
110 cond->ptc_magic = _PT_COND_DEAD;
111 free(cond->ptc_private);
112
113 return 0;
114 }
115
116 int
117 pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
118 const struct timespec *abstime)
119 {
120 pthread_t self;
121 int retval;
122
123 pthread__error(EINVAL, "Invalid condition variable",
124 cond->ptc_magic == _PT_COND_MAGIC);
125 pthread__error(EINVAL, "Invalid mutex",
126 mutex->ptm_magic == _PT_MUTEX_MAGIC);
127 pthread__error(EPERM, "Mutex not locked in condition wait",
128 mutex->ptm_owner != NULL);
129 if (abstime != NULL) {
130 pthread__error(EINVAL, "Invalid wait time",
131 (abstime->tv_sec >= 0) &&
132 (abstime->tv_nsec >= 0) &&
133 (abstime->tv_nsec < 1000000000));
134 }
135
136 self = pthread__self();
137
138 /* Just hang out for a while if threads aren't running yet. */
139 if (__predict_false(pthread__started == 0)) {
140 return pthread_cond_wait_nothread(self, mutex, cond, abstime);
141 }
142 if (__predict_false(self->pt_cancel)) {
143 pthread__cancelled();
144 }
145
146 /* Note this thread as waiting on the CV. */
147 pthread__spinlock(self, &cond->ptc_lock);
148 cond->ptc_mutex = mutex;
149 PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep);
150 self->pt_sleepobj = cond;
151 pthread__spinunlock(self, &cond->ptc_lock);
152
153 do {
154 self->pt_willpark = 1;
155 pthread_mutex_unlock(mutex);
156 self->pt_willpark = 0;
157 self->pt_blocking++;
158 retval = _lwp_park(abstime, self->pt_unpark,
159 __UNVOLATILE(&mutex->ptm_waiters),
160 __UNVOLATILE(&mutex->ptm_waiters));
161 self->pt_unpark = 0;
162 self->pt_blocking--;
163 membar_sync();
164 pthread_mutex_lock(mutex);
165
166 /*
167 * If we have cancelled then exit. POSIX dictates that
168 * the mutex must be held when we action the cancellation.
169 *
170 * If we absorbed a pthread_cond_signal() and cannot take
171 * the wakeup, we must ensure that another thread does.
172 *
173 * If awoke early, we may still be on the sleep queue and
174 * must remove ourself.
175 */
176 if (__predict_false(retval != 0)) {
177 switch (errno) {
178 case EINTR:
179 case EALREADY:
180 retval = 0;
181 break;
182 default:
183 retval = errno;
184 break;
185 }
186 }
187 if (__predict_false(self->pt_cancel | retval)) {
188 pthread_cond_signal(cond);
189 if (self->pt_cancel) {
190 pthread__cancelled();
191 }
192 break;
193 }
194 } while (self->pt_sleepobj != NULL);
195
196 return retval;
197 }
198
199 int
200 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
201 {
202
203 return pthread_cond_timedwait(cond, mutex, NULL);
204 }
205
206 static int __noinline
207 pthread__cond_wake_one(pthread_cond_t *cond)
208 {
209 pthread_t self, signaled;
210 pthread_mutex_t *mutex;
211 lwpid_t lid;
212
213 pthread__error(EINVAL, "Invalid condition variable",
214 cond->ptc_magic == _PT_COND_MAGIC);
215
216 /*
217 * Pull the first thread off the queue. If the current thread
218 * is associated with the condition variable, remove it without
219 * awakening (error case in pthread_cond_timedwait()).
220 */
221 self = pthread__self();
222 pthread__spinlock(self, &cond->ptc_lock);
223 if (self->pt_sleepobj == cond) {
224 PTQ_REMOVE(&cond->ptc_waiters, self, pt_sleep);
225 self->pt_sleepobj = NULL;
226 }
227 signaled = PTQ_FIRST(&cond->ptc_waiters);
228 if (__predict_false(signaled == NULL)) {
229 cond->ptc_mutex = NULL;
230 pthread__spinunlock(self, &cond->ptc_lock);
231 return 0;
232 }
233 mutex = cond->ptc_mutex;
234 if (PTQ_NEXT(signaled, pt_sleep) == NULL) {
235 cond->ptc_mutex = NULL;
236 PTQ_INIT(&cond->ptc_waiters);
237 } else {
238 PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
239 }
240 signaled->pt_sleepobj = NULL;
241 lid = signaled->pt_lid;
242 pthread__spinunlock(self, &cond->ptc_lock);
243
244 /*
245 * For all valid uses of pthread_cond_signal(), the caller will
246 * hold the mutex that the target is using to synchronize with.
247 * To avoid the target awakening and immediately blocking on the
248 * mutex, transfer the thread to be awoken to the current thread's
249 * deferred wakeup list. The waiter will be set running when the
250 * caller (this thread) releases the mutex.
251 */
252 if (__predict_false(self->pt_nwaiters == (size_t)pthread__unpark_max)) {
253 (void)_lwp_unpark_all(self->pt_waiters, self->pt_nwaiters,
254 __UNVOLATILE(&mutex->ptm_waiters));
255 self->pt_nwaiters = 0;
256 }
257 self->pt_waiters[self->pt_nwaiters++] = lid;
258 pthread__mutex_deferwake(self, mutex);
259 return 0;
260 }
261
262 int
263 pthread_cond_signal(pthread_cond_t *cond)
264 {
265
266 if (__predict_true(PTQ_EMPTY(&cond->ptc_waiters)))
267 return 0;
268 return pthread__cond_wake_one(cond);
269 }
270
271 static int __noinline
272 pthread__cond_wake_all(pthread_cond_t *cond)
273 {
274 pthread_t self, signaled;
275 pthread_mutex_t *mutex;
276 u_int max;
277 size_t nwaiters;
278
279 pthread__error(EINVAL, "Invalid condition variable",
280 cond->ptc_magic == _PT_COND_MAGIC);
281
282 /*
283 * Try to defer waking threads (see pthread_cond_signal()).
284 * Only transfer waiters for which there is no pending wakeup.
285 */
286 self = pthread__self();
287 pthread__spinlock(self, &cond->ptc_lock);
288 max = pthread__unpark_max;
289 mutex = cond->ptc_mutex;
290 nwaiters = self->pt_nwaiters;
291 PTQ_FOREACH(signaled, &cond->ptc_waiters, pt_sleep) {
292 if (__predict_false(nwaiters == max)) {
293 /* Overflow. */
294 (void)_lwp_unpark_all(self->pt_waiters,
295 nwaiters, __UNVOLATILE(&mutex->ptm_waiters));
296 nwaiters = 0;
297 }
298 signaled->pt_sleepobj = NULL;
299 self->pt_waiters[nwaiters++] = signaled->pt_lid;
300 }
301 PTQ_INIT(&cond->ptc_waiters);
302 self->pt_nwaiters = nwaiters;
303 cond->ptc_mutex = NULL;
304 pthread__spinunlock(self, &cond->ptc_lock);
305 pthread__mutex_deferwake(self, mutex);
306
307 return 0;
308 }
309
310 int
311 pthread_cond_broadcast(pthread_cond_t *cond)
312 {
313
314 if (__predict_true(PTQ_EMPTY(&cond->ptc_waiters)))
315 return 0;
316 return pthread__cond_wake_all(cond);
317 }
318
319 int
320 _pthread_cond_has_waiters_np(pthread_cond_t *cond)
321 {
322
323 return !PTQ_EMPTY(&cond->ptc_waiters);
324 }
325
326 int
327 pthread_condattr_init(pthread_condattr_t *attr)
328 {
329
330 attr->ptca_magic = _PT_CONDATTR_MAGIC;
331 attr->ptca_private = NULL;
332
333 return 0;
334 }
335
336 int
337 pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clck)
338 {
339 switch (clck) {
340 case CLOCK_MONOTONIC:
341 case CLOCK_REALTIME:
342 if (attr->ptca_private == NULL)
343 attr->ptca_private = malloc(sizeof(clockid_t));
344 if (attr->ptca_private == NULL)
345 return errno;
346 *(clockid_t *)attr->ptca_private = clck;
347 return 0;
348 default:
349 return EINVAL;
350 }
351 }
352
353 int
354 pthread_condattr_destroy(pthread_condattr_t *attr)
355 {
356
357 pthread__error(EINVAL, "Invalid condition variable attribute",
358 attr->ptca_magic == _PT_CONDATTR_MAGIC);
359
360 attr->ptca_magic = _PT_CONDATTR_DEAD;
361 free(attr->ptca_private);
362
363 return 0;
364 }
365
366 /* Utility routine to hang out for a while if threads haven't started yet. */
367 static int
368 pthread_cond_wait_nothread(pthread_t self, pthread_mutex_t *mutex,
369 pthread_cond_t *cond, const struct timespec *abstime)
370 {
371 struct timespec now, diff;
372 int retval;
373
374 if (abstime == NULL) {
375 diff.tv_sec = 99999999;
376 diff.tv_nsec = 0;
377 } else {
378 clockid_t clck = cond->ptc_private ?
379 *(clockid_t *)cond->ptc_private : CLOCK_REALTIME;
380 clock_gettime(clck, &now);
381 if (timespeccmp(abstime, &now, <))
382 timespecclear(&diff);
383 else
384 timespecsub(abstime, &now, &diff);
385 }
386
387 do {
388 pthread__testcancel(self);
389 pthread_mutex_unlock(mutex);
390 retval = _sys___nanosleep50(&diff, NULL);
391 pthread_mutex_lock(mutex);
392 } while (abstime == NULL && retval == 0);
393 pthread__testcancel(self);
394
395 if (retval == 0)
396 return ETIMEDOUT;
397 else
398 /* spurious wakeup */
399 return 0;
400 }
401