Home | History | Annotate | Line # | Download | only in libpthread
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