Home | History | Annotate | Line # | Download | only in libpthread
pthread_cond.c revision 1.38
      1  1.38       ad /*	$NetBSD: pthread_cond.c,v 1.38 2007/11/13 15:57:11 ad Exp $	*/
      2   1.2  thorpej 
      3   1.2  thorpej /*-
      4  1.22       ad  * Copyright (c) 2001, 2006, 2007 The NetBSD Foundation, Inc.
      5   1.2  thorpej  * All rights reserved.
      6   1.2  thorpej  *
      7   1.2  thorpej  * This code is derived from software contributed to The NetBSD Foundation
      8  1.26       ad  * by Nathan J. Williams and Andrew Doran.
      9   1.2  thorpej  *
     10   1.2  thorpej  * Redistribution and use in source and binary forms, with or without
     11   1.2  thorpej  * modification, are permitted provided that the following conditions
     12   1.2  thorpej  * are met:
     13   1.2  thorpej  * 1. Redistributions of source code must retain the above copyright
     14   1.2  thorpej  *    notice, this list of conditions and the following disclaimer.
     15   1.2  thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     16   1.2  thorpej  *    notice, this list of conditions and the following disclaimer in the
     17   1.2  thorpej  *    documentation and/or other materials provided with the distribution.
     18   1.2  thorpej  * 3. All advertising materials mentioning features or use of this software
     19   1.2  thorpej  *    must display the following acknowledgement:
     20   1.2  thorpej  *        This product includes software developed by the NetBSD
     21   1.2  thorpej  *        Foundation, Inc. and its contributors.
     22   1.2  thorpej  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23   1.2  thorpej  *    contributors may be used to endorse or promote products derived
     24   1.2  thorpej  *    from this software without specific prior written permission.
     25   1.2  thorpej  *
     26   1.2  thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27   1.2  thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28   1.2  thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29   1.2  thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30   1.2  thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31   1.2  thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32   1.2  thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33   1.2  thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34   1.2  thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35   1.2  thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36   1.2  thorpej  * POSSIBILITY OF SUCH DAMAGE.
     37   1.2  thorpej  */
     38   1.2  thorpej 
     39   1.8    lukem #include <sys/cdefs.h>
     40  1.38       ad __RCSID("$NetBSD: pthread_cond.c,v 1.38 2007/11/13 15:57:11 ad Exp $");
     41   1.8    lukem 
     42   1.2  thorpej #include <errno.h>
     43   1.6  nathanw #include <sys/time.h>
     44   1.6  nathanw #include <sys/types.h>
     45   1.2  thorpej 
     46   1.2  thorpej #include "pthread.h"
     47   1.2  thorpej #include "pthread_int.h"
     48   1.2  thorpej 
     49  1.18  mycroft int	_sys_nanosleep(const struct timespec *, struct timespec *);
     50   1.6  nathanw 
     51   1.6  nathanw extern int pthread__started;
     52   1.6  nathanw 
     53   1.6  nathanw static int pthread_cond_wait_nothread(pthread_t, pthread_mutex_t *,
     54   1.6  nathanw     const struct timespec *);
     55   1.2  thorpej 
     56   1.2  thorpej __strong_alias(__libc_cond_init,pthread_cond_init)
     57   1.2  thorpej __strong_alias(__libc_cond_signal,pthread_cond_signal)
     58   1.2  thorpej __strong_alias(__libc_cond_broadcast,pthread_cond_broadcast)
     59   1.2  thorpej __strong_alias(__libc_cond_wait,pthread_cond_wait)
     60   1.2  thorpej __strong_alias(__libc_cond_timedwait,pthread_cond_timedwait)
     61   1.2  thorpej __strong_alias(__libc_cond_destroy,pthread_cond_destroy)
     62   1.2  thorpej 
     63   1.2  thorpej int
     64   1.2  thorpej pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
     65   1.2  thorpej {
     66   1.2  thorpej 
     67  1.11  nathanw 	pthread__error(EINVAL, "Invalid condition variable attribute",
     68  1.11  nathanw 	    (attr == NULL) || (attr->ptca_magic == _PT_CONDATTR_MAGIC));
     69   1.2  thorpej 
     70   1.2  thorpej 	cond->ptc_magic = _PT_COND_MAGIC;
     71   1.2  thorpej 	pthread_lockinit(&cond->ptc_lock);
     72   1.2  thorpej 	PTQ_INIT(&cond->ptc_waiters);
     73   1.2  thorpej 	cond->ptc_mutex = NULL;
     74   1.2  thorpej 
     75   1.2  thorpej 	return 0;
     76   1.2  thorpej }
     77   1.2  thorpej 
     78   1.2  thorpej 
     79   1.2  thorpej int
     80   1.2  thorpej pthread_cond_destroy(pthread_cond_t *cond)
     81   1.2  thorpej {
     82   1.2  thorpej 
     83  1.11  nathanw 	pthread__error(EINVAL, "Invalid condition variable",
     84  1.11  nathanw 	    cond->ptc_magic == _PT_COND_MAGIC);
     85  1.11  nathanw 	pthread__error(EBUSY, "Destroying condition variable in use",
     86  1.11  nathanw 	    cond->ptc_mutex == NULL);
     87   1.2  thorpej 
     88   1.2  thorpej 	cond->ptc_magic = _PT_COND_DEAD;
     89   1.2  thorpej 
     90   1.2  thorpej 	return 0;
     91   1.2  thorpej }
     92   1.2  thorpej 
     93   1.2  thorpej 
     94   1.2  thorpej int
     95   1.2  thorpej pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
     96   1.2  thorpej {
     97   1.2  thorpej 	pthread_t self;
     98  1.10  nathanw 
     99  1.11  nathanw 	pthread__error(EINVAL, "Invalid condition variable",
    100  1.11  nathanw 	    cond->ptc_magic == _PT_COND_MAGIC);
    101  1.11  nathanw 	pthread__error(EINVAL, "Invalid mutex",
    102  1.11  nathanw 	    mutex->ptm_magic == _PT_MUTEX_MAGIC);
    103  1.11  nathanw 	pthread__error(EPERM, "Mutex not locked in condition wait",
    104  1.35       ad 	    mutex->ptm_owner != NULL);
    105  1.10  nathanw 
    106   1.2  thorpej 	self = pthread__self();
    107   1.3  nathanw 	PTHREADD_ADD(PTHREADD_COND_WAIT);
    108   1.6  nathanw 
    109   1.6  nathanw 	/* Just hang out for a while if threads aren't running yet. */
    110   1.6  nathanw 	if (__predict_false(pthread__started == 0))
    111   1.6  nathanw 		return pthread_cond_wait_nothread(self, mutex, NULL);
    112   1.6  nathanw 
    113  1.25       ad 	if (__predict_false(self->pt_cancel))
    114  1.21       ad 		pthread_exit(PTHREAD_CANCELED);
    115  1.32       ad 
    116  1.32       ad 	/*
    117  1.32       ad 	 * Note this thread as waiting on the CV.  To ensure good
    118  1.32       ad 	 * performance it's critical that the spinlock is held for
    119  1.32       ad 	 * as short a time as possible - that means no system calls.
    120  1.32       ad 	 */
    121  1.38       ad 	pthread__spinlock(self, &cond->ptc_lock);
    122  1.36       ad #ifdef ERRORCHECK
    123  1.21       ad 	if (cond->ptc_mutex == NULL)
    124  1.21       ad 		cond->ptc_mutex = mutex;
    125  1.28       ad 	else {
    126  1.21       ad 		pthread__error(EINVAL,
    127  1.21       ad 		    "Multiple mutexes used for condition wait",
    128  1.21       ad 		    cond->ptc_mutex == mutex);
    129  1.36       ad 	}
    130  1.36       ad #else
    131  1.36       ad 	cond->ptc_mutex = mutex;
    132  1.21       ad #endif
    133  1.23       ad 	PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep);
    134  1.31       ad 	self->pt_signalled = 0;
    135  1.23       ad 	self->pt_sleeponq = 1;
    136  1.26       ad 	self->pt_sleepobj = &cond->ptc_waiters;
    137  1.38       ad 	pthread__spinunlock(self, &cond->ptc_lock);
    138  1.32       ad 
    139  1.33       ad  	/*
    140  1.33       ad  	 * Before releasing the mutex, note that this thread is
    141  1.33       ad  	 * about to block by setting the willpark flag.  If there
    142  1.33       ad  	 * is a single waiter on the mutex, setting the flag will
    143  1.33       ad  	 * defer restarting it until calling into the kernel to
    144  1.33       ad  	 * park, saving a syscall & involuntary context switch.
    145  1.33       ad  	 */
    146  1.33       ad 	self->pt_willpark = 1;
    147  1.19       ad 	pthread_mutex_unlock(mutex);
    148  1.26       ad 	(void)pthread__park(self, &cond->ptc_lock, &cond->ptc_waiters,
    149  1.30       ad 	    NULL, 1, &mutex->ptm_blocked);
    150  1.35       ad 	pthread_mutex_lock(mutex);
    151  1.32       ad 
    152  1.32       ad 	/*
    153  1.32       ad 	 * If we awoke abnormally the waiters list will have been
    154  1.32       ad 	 * made empty by the current thread (in pthread__park()),
    155  1.32       ad 	 * so we can check the value safely without locking.
    156  1.32       ad 	 *
    157  1.32       ad 	 * Otherwise, it will have been updated by whichever thread
    158  1.32       ad 	 * last issued a wakeup.
    159  1.32       ad 	 */
    160  1.32       ad 	if (PTQ_EMPTY(&cond->ptc_waiters) && cond->ptc_mutex != NULL) {
    161  1.38       ad 		pthread__spinlock(self, &cond->ptc_lock);
    162  1.32       ad 		if (PTQ_EMPTY(&cond->ptc_waiters))
    163  1.32       ad 			cond->ptc_mutex = NULL;
    164  1.38       ad 		pthread__spinunlock(self, &cond->ptc_lock);
    165  1.32       ad 	}
    166  1.32       ad 
    167  1.32       ad 	/*
    168  1.35       ad 	 * If we have cancelled then exit.  POSIX dictates that the
    169  1.35       ad 	 * mutex must be held when we action the cancellation.
    170  1.32       ad 	 */
    171  1.31       ad 	if (__predict_false(self->pt_cancel)) {
    172  1.31       ad 		if (self->pt_signalled)
    173  1.31       ad 			pthread_cond_signal(cond);
    174  1.12  nathanw 		pthread_exit(PTHREAD_CANCELED);
    175  1.31       ad 	}
    176  1.12  nathanw 
    177   1.2  thorpej 	return 0;
    178   1.2  thorpej }
    179   1.2  thorpej 
    180   1.2  thorpej int
    181   1.2  thorpej pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
    182   1.2  thorpej     const struct timespec *abstime)
    183   1.2  thorpej {
    184   1.2  thorpej 	pthread_t self;
    185   1.2  thorpej 	int retval;
    186   1.2  thorpej 
    187  1.11  nathanw 	pthread__error(EINVAL, "Invalid condition variable",
    188  1.11  nathanw 	    cond->ptc_magic == _PT_COND_MAGIC);
    189  1.11  nathanw 	pthread__error(EINVAL, "Invalid mutex",
    190  1.11  nathanw 	    mutex->ptm_magic == _PT_MUTEX_MAGIC);
    191  1.11  nathanw 	pthread__error(EPERM, "Mutex not locked in condition wait",
    192  1.35       ad 	    mutex->ptm_owner != NULL);
    193  1.11  nathanw 	pthread__error(EINVAL, "Invalid wait time",
    194  1.11  nathanw 	    (abstime->tv_sec >= 0) &&
    195  1.10  nathanw 	    (abstime->tv_nsec >= 0) && (abstime->tv_nsec < 1000000000));
    196  1.10  nathanw 
    197   1.2  thorpej 	self = pthread__self();
    198   1.6  nathanw 	PTHREADD_ADD(PTHREADD_COND_TIMEDWAIT);
    199   1.6  nathanw 
    200   1.6  nathanw 	/* Just hang out for a while if threads aren't running yet. */
    201   1.6  nathanw 	if (__predict_false(pthread__started == 0))
    202   1.6  nathanw 		return pthread_cond_wait_nothread(self, mutex, abstime);
    203   1.6  nathanw 
    204  1.25       ad 	if (__predict_false(self->pt_cancel))
    205  1.21       ad 		pthread_exit(PTHREAD_CANCELED);
    206  1.32       ad 
    207  1.32       ad 	/*
    208  1.32       ad 	 * Note this thread as waiting on the CV.  To ensure good
    209  1.32       ad 	 * performance it's critical that the spinlock is held for
    210  1.32       ad 	 * as short a time as possible - that means no system calls.
    211  1.32       ad 	 */
    212  1.38       ad 	pthread__spinlock(self, &cond->ptc_lock);
    213  1.36       ad #ifdef ERRORCHECK
    214  1.21       ad 	if (cond->ptc_mutex == NULL)
    215  1.21       ad 		cond->ptc_mutex = mutex;
    216  1.28       ad 	else {
    217  1.21       ad 		pthread__error(EINVAL,
    218  1.21       ad 		    "Multiple mutexes used for condition wait",
    219  1.21       ad 		    cond->ptc_mutex == mutex);
    220  1.36       ad 	}
    221  1.36       ad #else
    222  1.36       ad 	cond->ptc_mutex = mutex;
    223  1.21       ad #endif
    224  1.23       ad 	PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep);
    225  1.31       ad 	self->pt_signalled = 0;
    226  1.23       ad 	self->pt_sleeponq = 1;
    227  1.26       ad 	self->pt_sleepobj = &cond->ptc_waiters;
    228  1.38       ad 	pthread__spinunlock(self, &cond->ptc_lock);
    229  1.32       ad 
    230  1.33       ad  	/*
    231  1.33       ad  	 * Before releasing the mutex, note that this thread is
    232  1.33       ad  	 * about to block by setting the willpark flag.  If there
    233  1.33       ad  	 * is a single waiter on the mutex, setting the flag will
    234  1.33       ad  	 * defer restarting it until calling into the kernel to
    235  1.33       ad  	 * park, saving a syscall & involuntary context switch.
    236  1.33       ad  	 */
    237  1.33       ad 	self->pt_willpark = 1;
    238  1.20       ad 	pthread_mutex_unlock(mutex);
    239  1.26       ad 	retval = pthread__park(self, &cond->ptc_lock, &cond->ptc_waiters,
    240  1.30       ad 	    abstime, 1, &mutex->ptm_blocked);
    241  1.35       ad 	pthread_mutex_lock(mutex);
    242  1.19       ad 
    243  1.32       ad 	/*
    244  1.32       ad 	 * If we awoke abnormally the waiters list will have been
    245  1.32       ad 	 * made empty by the current thread (in pthread__park()),
    246  1.32       ad 	 * so we can check the value safely without locking.
    247  1.32       ad 	 *
    248  1.32       ad 	 * Otherwise, it will have been updated by whichever thread
    249  1.32       ad 	 * last issued a wakeup.
    250  1.32       ad 	 */
    251  1.32       ad 	if (PTQ_EMPTY(&cond->ptc_waiters) && cond->ptc_mutex != NULL) {
    252  1.38       ad 		pthread__spinlock(self, &cond->ptc_lock);
    253  1.32       ad 		if (PTQ_EMPTY(&cond->ptc_waiters))
    254  1.32       ad 			cond->ptc_mutex = NULL;
    255  1.38       ad 		pthread__spinunlock(self, &cond->ptc_lock);
    256  1.32       ad 	}
    257  1.32       ad 
    258  1.32       ad 	/*
    259  1.35       ad 	 * If we have cancelled then exit.  POSIX dictates that the
    260  1.35       ad 	 * mutex must be held when we action the cancellation.
    261  1.32       ad 	 */
    262  1.31       ad 	if (__predict_false(self->pt_cancel | retval)) {
    263  1.31       ad 		if (self->pt_signalled)
    264  1.31       ad 			pthread_cond_signal(cond);
    265  1.31       ad 		if (self->pt_cancel)
    266  1.31       ad 			pthread_exit(PTHREAD_CANCELED);
    267  1.31       ad 	}
    268   1.2  thorpej 
    269   1.2  thorpej 	return retval;
    270   1.2  thorpej }
    271   1.2  thorpej 
    272   1.2  thorpej int
    273   1.2  thorpej pthread_cond_signal(pthread_cond_t *cond)
    274   1.2  thorpej {
    275   1.2  thorpej 	pthread_t self, signaled;
    276  1.28       ad 	pthread_mutex_t *mutex;
    277  1.10  nathanw 
    278  1.11  nathanw 	pthread__error(EINVAL, "Invalid condition variable",
    279  1.11  nathanw 	    cond->ptc_magic == _PT_COND_MAGIC);
    280   1.3  nathanw 	PTHREADD_ADD(PTHREADD_COND_SIGNAL);
    281   1.2  thorpej 
    282  1.27       ad 	if (PTQ_EMPTY(&cond->ptc_waiters))
    283  1.27       ad 		return 0;
    284  1.27       ad 
    285  1.27       ad 	self = pthread__self();
    286  1.38       ad 	pthread__spinlock(self, &cond->ptc_lock);
    287  1.28       ad 
    288  1.28       ad 	/*
    289  1.28       ad 	 * Find a thread that is still blocked (no pending wakeup).
    290  1.28       ad 	 * A wakeup can be pending if we have interrupted unpark_all
    291  1.28       ad 	 * as it releases the interlock.
    292  1.28       ad 	 */
    293  1.28       ad 	PTQ_FOREACH(signaled, &cond->ptc_waiters, pt_sleep) {
    294  1.28       ad 		if (signaled->pt_sleepobj != NULL)
    295  1.28       ad 			break;
    296  1.28       ad 	}
    297  1.28       ad 	if (__predict_false(signaled == NULL)) {
    298  1.28       ad 		cond->ptc_mutex = NULL;
    299  1.38       ad 		pthread__spinunlock(self, &cond->ptc_lock);
    300  1.28       ad 		return 0;
    301  1.28       ad 	}
    302  1.28       ad 
    303  1.28       ad 	/*
    304  1.31       ad 	 * Pull the thread off the queue, and set pt_signalled.
    305  1.31       ad 	 *
    306  1.31       ad 	 * After resuming execution, the thread must check to see if it
    307  1.31       ad 	 * has been restarted as a result of pthread_cond_signal().  If it
    308  1.32       ad 	 * has, but cannot take the wakeup (because of eg a timeout) then
    309  1.32       ad 	 * try to ensure that another thread sees it.  This is necessary
    310  1.32       ad 	 * because there may be multiple waiters, and at least one should
    311  1.32       ad 	 * take the wakeup if possible.
    312  1.28       ad 	 */
    313  1.28       ad 	PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
    314  1.28       ad 	mutex = cond->ptc_mutex;
    315  1.28       ad 	if (PTQ_EMPTY(&cond->ptc_waiters))
    316  1.28       ad 		cond->ptc_mutex = NULL;
    317  1.31       ad 	signaled->pt_signalled = 1;
    318  1.28       ad 
    319  1.28       ad 	/*
    320  1.28       ad 	 * For all valid uses of pthread_cond_signal(), the caller will
    321  1.28       ad 	 * hold the mutex that the target is using to synchronize with.
    322  1.28       ad 	 * To avoid the target awakening and immediatley blocking on the
    323  1.35       ad 	 * mutex, transfer the thread to be awoken to the current thread's
    324  1.35       ad 	 * deferred wakeup list.  The waiter will be set running when the
    325  1.35       ad 	 * caller (this thread) releases the mutex.
    326  1.28       ad 	 */
    327  1.37       ad 	if (mutex != NULL && self->pt_nwaiters < pthread__unpark_max &&
    328  1.37       ad 	    pthread__mutex_deferwake(self, mutex)) {
    329  1.35       ad 		signaled->pt_sleepobj = NULL;
    330  1.35       ad 		signaled->pt_sleeponq = 0;
    331  1.38       ad 		pthread__spinunlock(self, &cond->ptc_lock);
    332  1.35       ad 		self->pt_waiters[self->pt_nwaiters++] = signaled->pt_lid;
    333  1.28       ad 	} else {
    334  1.27       ad 		pthread__unpark(self, &cond->ptc_lock,
    335  1.27       ad 		    &cond->ptc_waiters, signaled);
    336   1.4  nathanw 	}
    337  1.29       ad 	PTHREADD_ADD(PTHREADD_COND_WOKEUP);
    338  1.22       ad 
    339   1.2  thorpej 	return 0;
    340   1.2  thorpej }
    341   1.2  thorpej 
    342   1.2  thorpej 
    343   1.2  thorpej int
    344   1.2  thorpej pthread_cond_broadcast(pthread_cond_t *cond)
    345   1.2  thorpej {
    346  1.28       ad 	pthread_t self, signaled, next;
    347  1.28       ad 	pthread_mutex_t *mutex;
    348  1.10  nathanw 
    349  1.28       ad 	pthread__error(EINVAL, "Invalid condition variable",
    350  1.28       ad 	    cond->ptc_magic == _PT_COND_MAGIC);
    351   1.2  thorpej 
    352   1.3  nathanw 	PTHREADD_ADD(PTHREADD_COND_BROADCAST);
    353   1.2  thorpej 
    354  1.27       ad 	if (PTQ_EMPTY(&cond->ptc_waiters))
    355  1.27       ad 		return 0;
    356  1.27       ad 
    357  1.27       ad 	self = pthread__self();
    358  1.38       ad 	pthread__spinlock(self, &cond->ptc_lock);
    359  1.28       ad 	mutex = cond->ptc_mutex;
    360  1.27       ad 	cond->ptc_mutex = NULL;
    361  1.28       ad 
    362  1.28       ad 	/*
    363  1.35       ad 	 * Try to defer waking threads (see pthread_cond_signal()).
    364  1.35       ad 	 * Only transfer waiters for which there is no pending wakeup.
    365  1.28       ad 	 */
    366  1.37       ad 	if (mutex != NULL && pthread__mutex_deferwake(self, mutex)) {
    367  1.28       ad 		for (signaled = PTQ_FIRST(&cond->ptc_waiters);
    368  1.28       ad 		    signaled != NULL;
    369  1.28       ad 		    signaled = next) {
    370  1.28       ad 		    	next = PTQ_NEXT(signaled, pt_sleep);
    371  1.28       ad 		    	if (__predict_false(signaled->pt_sleepobj == NULL))
    372  1.28       ad 		    		continue;
    373  1.35       ad 			if (self->pt_nwaiters == pthread__unpark_max) {
    374  1.35       ad 				/* Overflow, take the slow path. */
    375  1.35       ad 				break;
    376  1.35       ad 			}
    377  1.28       ad 		    	PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
    378  1.35       ad 			signaled->pt_sleepobj = NULL;
    379  1.35       ad 			signaled->pt_sleeponq = 0;
    380  1.35       ad 			self->pt_waiters[self->pt_nwaiters++] =
    381  1.35       ad 			    signaled->pt_lid;
    382  1.35       ad 		}
    383  1.35       ad 		if (signaled == NULL) {
    384  1.35       ad 			/* Anything more to do? */
    385  1.38       ad 			pthread__spinunlock(self, &cond->ptc_lock);
    386  1.35       ad 			return 0;
    387  1.28       ad 		}
    388  1.35       ad 	}
    389  1.35       ad 	pthread__unpark_all(self, &cond->ptc_lock, &cond->ptc_waiters);
    390  1.28       ad 
    391  1.27       ad 	PTHREADD_ADD(PTHREADD_COND_WOKEUP);
    392   1.2  thorpej 
    393   1.2  thorpej 	return 0;
    394   1.2  thorpej 
    395   1.2  thorpej }
    396   1.2  thorpej 
    397   1.2  thorpej 
    398   1.2  thorpej int
    399   1.2  thorpej pthread_condattr_init(pthread_condattr_t *attr)
    400   1.2  thorpej {
    401   1.2  thorpej 
    402   1.2  thorpej 	attr->ptca_magic = _PT_CONDATTR_MAGIC;
    403   1.2  thorpej 
    404   1.2  thorpej 	return 0;
    405   1.2  thorpej }
    406   1.2  thorpej 
    407   1.2  thorpej 
    408   1.2  thorpej int
    409   1.2  thorpej pthread_condattr_destroy(pthread_condattr_t *attr)
    410   1.2  thorpej {
    411   1.2  thorpej 
    412  1.11  nathanw 	pthread__error(EINVAL, "Invalid condition variable attribute",
    413  1.11  nathanw 	    attr->ptca_magic == _PT_CONDATTR_MAGIC);
    414   1.2  thorpej 
    415   1.2  thorpej 	attr->ptca_magic = _PT_CONDATTR_DEAD;
    416   1.2  thorpej 
    417   1.2  thorpej 	return 0;
    418   1.6  nathanw }
    419   1.6  nathanw 
    420   1.6  nathanw /* Utility routine to hang out for a while if threads haven't started yet. */
    421   1.6  nathanw static int
    422   1.6  nathanw pthread_cond_wait_nothread(pthread_t self, pthread_mutex_t *mutex,
    423   1.6  nathanw     const struct timespec *abstime)
    424   1.6  nathanw {
    425  1.18  mycroft 	struct timespec now, diff;
    426   1.6  nathanw 	int retval;
    427   1.6  nathanw 
    428  1.18  mycroft 	if (abstime == NULL) {
    429  1.18  mycroft 		diff.tv_sec = 99999999;
    430  1.18  mycroft 		diff.tv_nsec = 0;
    431  1.18  mycroft 	} else {
    432  1.18  mycroft 		clock_gettime(CLOCK_REALTIME, &now);
    433  1.18  mycroft 		if  (timespeccmp(abstime, &now, <))
    434  1.18  mycroft 			timespecclear(&diff);
    435  1.17  nathanw 		else
    436  1.18  mycroft 			timespecsub(abstime, &now, &diff);
    437   1.6  nathanw 	}
    438   1.6  nathanw 
    439  1.18  mycroft 	do {
    440  1.18  mycroft 		pthread__testcancel(self);
    441  1.18  mycroft 		pthread_mutex_unlock(mutex);
    442  1.18  mycroft 		retval = _sys_nanosleep(&diff, NULL);
    443  1.18  mycroft 		pthread_mutex_lock(mutex);
    444  1.18  mycroft 	} while (abstime == NULL && retval == 0);
    445   1.6  nathanw 	pthread__testcancel(self);
    446   1.6  nathanw 
    447   1.6  nathanw 	if (retval == 0)
    448   1.6  nathanw 		return ETIMEDOUT;
    449   1.6  nathanw 	else
    450  1.15   kleink 		/* spurious wakeup */
    451  1.15   kleink 		return 0;
    452   1.2  thorpej }
    453