xref: /netbsd-src/lib/libpthread/pthread_cond.c (revision 96fc3e30a7c3f7bba53384bf41dad5f78306fac4)
1 /*	$NetBSD: pthread_cond.c,v 1.58 2012/11/03 03:10:50 christos 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.58 2012/11/03 03:10:50 christos 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