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