Home | History | Annotate | Line # | Download | only in libpthread
pthread_cond.c revision 1.32
      1  1.32       ad /*	$NetBSD: pthread_cond.c,v 1.32 2007/08/04 13:37:49 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.32       ad __RCSID("$NetBSD: pthread_cond.c,v 1.32 2007/08/04 13:37:49 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.11  nathanw 	    mutex->ptm_lock == __SIMPLELOCK_LOCKED);
    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.21       ad 	pthread_spinlock(self, &cond->ptc_lock);
    122  1.21       ad 	if (cond->ptc_mutex == NULL)
    123  1.21       ad 		cond->ptc_mutex = mutex;
    124  1.28       ad 	else {
    125  1.28       ad #ifdef ERRORCHECK
    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.21       ad #endif
    130  1.28       ad 	}
    131  1.23       ad 	PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep);
    132  1.31       ad 	self->pt_signalled = 0;
    133  1.23       ad 	self->pt_sleeponq = 1;
    134  1.26       ad 	self->pt_sleepobj = &cond->ptc_waiters;
    135  1.32       ad 	pthread_spinunlock(self, &cond->ptc_lock);
    136  1.32       ad 
    137  1.32       ad 	/* Once recorded as a waiter release the mutex and sleep. */
    138  1.19       ad 	pthread_mutex_unlock(mutex);
    139  1.26       ad 	(void)pthread__park(self, &cond->ptc_lock, &cond->ptc_waiters,
    140  1.30       ad 	    NULL, 1, &mutex->ptm_blocked);
    141  1.32       ad 
    142  1.32       ad 	/*
    143  1.32       ad 	 * If we awoke abnormally the waiters list will have been
    144  1.32       ad 	 * made empty by the current thread (in pthread__park()),
    145  1.32       ad 	 * so we can check the value safely without locking.
    146  1.32       ad 	 *
    147  1.32       ad 	 * Otherwise, it will have been updated by whichever thread
    148  1.32       ad 	 * last issued a wakeup.
    149  1.32       ad 	 */
    150  1.32       ad 	if (PTQ_EMPTY(&cond->ptc_waiters) && cond->ptc_mutex != NULL) {
    151  1.32       ad 		pthread_spinlock(self, &cond->ptc_lock);
    152  1.32       ad 		if (PTQ_EMPTY(&cond->ptc_waiters))
    153  1.32       ad 			cond->ptc_mutex = NULL;
    154  1.32       ad 		pthread_spinunlock(self, &cond->ptc_lock);
    155  1.32       ad 	}
    156  1.32       ad 
    157  1.32       ad 	/*
    158  1.32       ad 	 * Re-acquire the mutex and return to the caller.  If we
    159  1.32       ad 	 * have cancelled then exit.  POSIX dictates that the mutex
    160  1.32       ad 	 * must be held when we action the cancellation.
    161  1.32       ad 	 */
    162  1.25       ad 	pthread_mutex_lock(mutex);
    163  1.31       ad 	if (__predict_false(self->pt_cancel)) {
    164  1.31       ad 		if (self->pt_signalled)
    165  1.31       ad 			pthread_cond_signal(cond);
    166  1.12  nathanw 		pthread_exit(PTHREAD_CANCELED);
    167  1.31       ad 	}
    168  1.12  nathanw 
    169   1.2  thorpej 	return 0;
    170   1.2  thorpej }
    171   1.2  thorpej 
    172   1.2  thorpej int
    173   1.2  thorpej pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
    174   1.2  thorpej     const struct timespec *abstime)
    175   1.2  thorpej {
    176   1.2  thorpej 	pthread_t self;
    177   1.2  thorpej 	int retval;
    178   1.2  thorpej 
    179  1.11  nathanw 	pthread__error(EINVAL, "Invalid condition variable",
    180  1.11  nathanw 	    cond->ptc_magic == _PT_COND_MAGIC);
    181  1.11  nathanw 	pthread__error(EINVAL, "Invalid mutex",
    182  1.11  nathanw 	    mutex->ptm_magic == _PT_MUTEX_MAGIC);
    183  1.11  nathanw 	pthread__error(EPERM, "Mutex not locked in condition wait",
    184  1.11  nathanw 	    mutex->ptm_lock == __SIMPLELOCK_LOCKED);
    185  1.11  nathanw 	pthread__error(EINVAL, "Invalid wait time",
    186  1.11  nathanw 	    (abstime->tv_sec >= 0) &&
    187  1.10  nathanw 	    (abstime->tv_nsec >= 0) && (abstime->tv_nsec < 1000000000));
    188  1.10  nathanw 
    189   1.2  thorpej 	self = pthread__self();
    190   1.6  nathanw 	PTHREADD_ADD(PTHREADD_COND_TIMEDWAIT);
    191   1.6  nathanw 
    192   1.6  nathanw 	/* Just hang out for a while if threads aren't running yet. */
    193   1.6  nathanw 	if (__predict_false(pthread__started == 0))
    194   1.6  nathanw 		return pthread_cond_wait_nothread(self, mutex, abstime);
    195   1.6  nathanw 
    196  1.25       ad 	if (__predict_false(self->pt_cancel))
    197  1.21       ad 		pthread_exit(PTHREAD_CANCELED);
    198  1.32       ad 
    199  1.32       ad 	/*
    200  1.32       ad 	 * Note this thread as waiting on the CV.  To ensure good
    201  1.32       ad 	 * performance it's critical that the spinlock is held for
    202  1.32       ad 	 * as short a time as possible - that means no system calls.
    203  1.32       ad 	 */
    204  1.21       ad 	pthread_spinlock(self, &cond->ptc_lock);
    205  1.21       ad 	if (cond->ptc_mutex == NULL)
    206  1.21       ad 		cond->ptc_mutex = mutex;
    207  1.28       ad 	else {
    208  1.28       ad #ifdef ERRORCHECK
    209  1.21       ad 		pthread__error(EINVAL,
    210  1.21       ad 		    "Multiple mutexes used for condition wait",
    211  1.21       ad 		    cond->ptc_mutex == mutex);
    212  1.21       ad #endif
    213  1.28       ad 	}
    214  1.23       ad 	PTQ_INSERT_HEAD(&cond->ptc_waiters, self, pt_sleep);
    215  1.31       ad 	self->pt_signalled = 0;
    216  1.23       ad 	self->pt_sleeponq = 1;
    217  1.26       ad 	self->pt_sleepobj = &cond->ptc_waiters;
    218  1.32       ad 	pthread_spinunlock(self, &cond->ptc_lock);
    219  1.32       ad 
    220  1.32       ad 	/* Once recorded as a waiter release the mutex and sleep. */
    221  1.20       ad 	pthread_mutex_unlock(mutex);
    222  1.26       ad 	retval = pthread__park(self, &cond->ptc_lock, &cond->ptc_waiters,
    223  1.30       ad 	    abstime, 1, &mutex->ptm_blocked);
    224  1.19       ad 
    225  1.32       ad 	/*
    226  1.32       ad 	 * If we awoke abnormally the waiters list will have been
    227  1.32       ad 	 * made empty by the current thread (in pthread__park()),
    228  1.32       ad 	 * so we can check the value safely without locking.
    229  1.32       ad 	 *
    230  1.32       ad 	 * Otherwise, it will have been updated by whichever thread
    231  1.32       ad 	 * last issued a wakeup.
    232  1.32       ad 	 */
    233  1.32       ad 	if (PTQ_EMPTY(&cond->ptc_waiters) && cond->ptc_mutex != NULL) {
    234  1.32       ad 		pthread_spinlock(self, &cond->ptc_lock);
    235  1.32       ad 		if (PTQ_EMPTY(&cond->ptc_waiters))
    236  1.32       ad 			cond->ptc_mutex = NULL;
    237  1.32       ad 		pthread_spinunlock(self, &cond->ptc_lock);
    238  1.32       ad 	}
    239  1.32       ad 
    240  1.32       ad 	/*
    241  1.32       ad 	 * Re-acquire the mutex and return to the caller.  If we
    242  1.32       ad 	 * have cancelled then exit.  POSIX dictates that the mutex
    243  1.32       ad 	 * must be held when we action the cancellation.
    244  1.32       ad 	 */
    245  1.25       ad 	pthread_mutex_lock(mutex);
    246  1.31       ad 	if (__predict_false(self->pt_cancel | retval)) {
    247  1.31       ad 		if (self->pt_signalled)
    248  1.31       ad 			pthread_cond_signal(cond);
    249  1.31       ad 		if (self->pt_cancel)
    250  1.31       ad 			pthread_exit(PTHREAD_CANCELED);
    251  1.31       ad 	}
    252   1.2  thorpej 
    253   1.2  thorpej 	return retval;
    254   1.2  thorpej }
    255   1.2  thorpej 
    256   1.2  thorpej int
    257   1.2  thorpej pthread_cond_signal(pthread_cond_t *cond)
    258   1.2  thorpej {
    259   1.2  thorpej 	pthread_t self, signaled;
    260  1.28       ad 	pthread_mutex_t *mutex;
    261  1.10  nathanw 
    262  1.11  nathanw 	pthread__error(EINVAL, "Invalid condition variable",
    263  1.11  nathanw 	    cond->ptc_magic == _PT_COND_MAGIC);
    264   1.3  nathanw 	PTHREADD_ADD(PTHREADD_COND_SIGNAL);
    265   1.2  thorpej 
    266  1.27       ad 	if (PTQ_EMPTY(&cond->ptc_waiters))
    267  1.27       ad 		return 0;
    268  1.27       ad 
    269  1.27       ad 	self = pthread__self();
    270  1.27       ad 	pthread_spinlock(self, &cond->ptc_lock);
    271  1.28       ad 
    272  1.28       ad 	/*
    273  1.28       ad 	 * Find a thread that is still blocked (no pending wakeup).
    274  1.28       ad 	 * A wakeup can be pending if we have interrupted unpark_all
    275  1.28       ad 	 * as it releases the interlock.
    276  1.28       ad 	 */
    277  1.28       ad 	PTQ_FOREACH(signaled, &cond->ptc_waiters, pt_sleep) {
    278  1.28       ad 		if (signaled->pt_sleepobj != NULL)
    279  1.28       ad 			break;
    280  1.28       ad 	}
    281  1.28       ad 	if (__predict_false(signaled == NULL)) {
    282  1.28       ad 		cond->ptc_mutex = NULL;
    283  1.28       ad 		pthread_spinunlock(self, &cond->ptc_lock);
    284  1.28       ad 		return 0;
    285  1.28       ad 	}
    286  1.28       ad 
    287  1.28       ad 	/*
    288  1.31       ad 	 * Pull the thread off the queue, and set pt_signalled.
    289  1.31       ad 	 *
    290  1.31       ad 	 * After resuming execution, the thread must check to see if it
    291  1.31       ad 	 * has been restarted as a result of pthread_cond_signal().  If it
    292  1.32       ad 	 * has, but cannot take the wakeup (because of eg a timeout) then
    293  1.32       ad 	 * try to ensure that another thread sees it.  This is necessary
    294  1.32       ad 	 * because there may be multiple waiters, and at least one should
    295  1.32       ad 	 * take the wakeup if possible.
    296  1.28       ad 	 */
    297  1.28       ad 	PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
    298  1.28       ad 	mutex = cond->ptc_mutex;
    299  1.28       ad 	if (PTQ_EMPTY(&cond->ptc_waiters))
    300  1.28       ad 		cond->ptc_mutex = NULL;
    301  1.31       ad 	signaled->pt_signalled = 1;
    302  1.28       ad 
    303  1.28       ad 	/*
    304  1.28       ad 	 * For all valid uses of pthread_cond_signal(), the caller will
    305  1.28       ad 	 * hold the mutex that the target is using to synchronize with.
    306  1.28       ad 	 * To avoid the target awakening and immediatley blocking on the
    307  1.28       ad 	 * mutex, transfer the thread to be awoken to the mutex's waiters
    308  1.28       ad 	 * list.  The waiter will be set running when the caller (this
    309  1.28       ad 	 * thread) releases the mutex.
    310  1.28       ad 	 */
    311  1.28       ad 	if (self->pt_mutexhint != NULL && self->pt_mutexhint == mutex) {
    312  1.28       ad 		pthread_spinunlock(self, &cond->ptc_lock);
    313  1.28       ad 		pthread_spinlock(self, &mutex->ptm_interlock);
    314  1.28       ad 		PTQ_INSERT_HEAD(&mutex->ptm_blocked, signaled, pt_sleep);
    315  1.28       ad 		pthread_spinunlock(self, &mutex->ptm_interlock);
    316  1.28       ad 	} else {
    317  1.27       ad 		pthread__unpark(self, &cond->ptc_lock,
    318  1.27       ad 		    &cond->ptc_waiters, signaled);
    319   1.4  nathanw 	}
    320  1.29       ad 	PTHREADD_ADD(PTHREADD_COND_WOKEUP);
    321  1.22       ad 
    322   1.2  thorpej 	return 0;
    323   1.2  thorpej }
    324   1.2  thorpej 
    325   1.2  thorpej 
    326   1.2  thorpej int
    327   1.2  thorpej pthread_cond_broadcast(pthread_cond_t *cond)
    328   1.2  thorpej {
    329  1.28       ad 	pthread_t self, signaled, next;
    330  1.28       ad 	pthread_mutex_t *mutex;
    331  1.10  nathanw 
    332  1.28       ad 	pthread__error(EINVAL, "Invalid condition variable",
    333  1.28       ad 	    cond->ptc_magic == _PT_COND_MAGIC);
    334   1.2  thorpej 
    335   1.3  nathanw 	PTHREADD_ADD(PTHREADD_COND_BROADCAST);
    336   1.2  thorpej 
    337  1.27       ad 	if (PTQ_EMPTY(&cond->ptc_waiters))
    338  1.27       ad 		return 0;
    339  1.27       ad 
    340  1.27       ad 	self = pthread__self();
    341  1.27       ad 	pthread_spinlock(self, &cond->ptc_lock);
    342  1.28       ad 	mutex = cond->ptc_mutex;
    343  1.27       ad 	cond->ptc_mutex = NULL;
    344  1.28       ad 
    345  1.28       ad 	/*
    346  1.28       ad 	 * Try to transfer waiters to the mutex's waiters list (see
    347  1.28       ad 	 * pthread_cond_signal()).  Only transfer waiters for which
    348  1.28       ad 	 * there is no pending wakeup.
    349  1.28       ad 	 */
    350  1.28       ad 	if (self->pt_mutexhint != NULL && self->pt_mutexhint == mutex) {
    351  1.28       ad 		pthread_spinlock(self, &mutex->ptm_interlock);
    352  1.28       ad 		for (signaled = PTQ_FIRST(&cond->ptc_waiters);
    353  1.28       ad 		    signaled != NULL;
    354  1.28       ad 		    signaled = next) {
    355  1.28       ad 		    	next = PTQ_NEXT(signaled, pt_sleep);
    356  1.28       ad 		    	if (__predict_false(signaled->pt_sleepobj == NULL))
    357  1.28       ad 		    		continue;
    358  1.28       ad 		    	PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
    359  1.28       ad 		    	PTQ_INSERT_HEAD(&mutex->ptm_blocked, signaled,
    360  1.28       ad 		    	    pt_sleep);
    361  1.28       ad 		}
    362  1.28       ad 		pthread_spinunlock(self, &mutex->ptm_interlock);
    363  1.28       ad 		pthread_spinunlock(self, &cond->ptc_lock);
    364  1.28       ad 	} else
    365  1.28       ad 		pthread__unpark_all(self, &cond->ptc_lock, &cond->ptc_waiters);
    366  1.28       ad 
    367  1.27       ad 	PTHREADD_ADD(PTHREADD_COND_WOKEUP);
    368   1.2  thorpej 
    369   1.2  thorpej 	return 0;
    370   1.2  thorpej 
    371   1.2  thorpej }
    372   1.2  thorpej 
    373   1.2  thorpej 
    374   1.2  thorpej int
    375   1.2  thorpej pthread_condattr_init(pthread_condattr_t *attr)
    376   1.2  thorpej {
    377   1.2  thorpej 
    378   1.2  thorpej 	attr->ptca_magic = _PT_CONDATTR_MAGIC;
    379   1.2  thorpej 
    380   1.2  thorpej 	return 0;
    381   1.2  thorpej }
    382   1.2  thorpej 
    383   1.2  thorpej 
    384   1.2  thorpej int
    385   1.2  thorpej pthread_condattr_destroy(pthread_condattr_t *attr)
    386   1.2  thorpej {
    387   1.2  thorpej 
    388  1.11  nathanw 	pthread__error(EINVAL, "Invalid condition variable attribute",
    389  1.11  nathanw 	    attr->ptca_magic == _PT_CONDATTR_MAGIC);
    390   1.2  thorpej 
    391   1.2  thorpej 	attr->ptca_magic = _PT_CONDATTR_DEAD;
    392   1.2  thorpej 
    393   1.2  thorpej 	return 0;
    394   1.6  nathanw }
    395   1.6  nathanw 
    396   1.6  nathanw /* Utility routine to hang out for a while if threads haven't started yet. */
    397   1.6  nathanw static int
    398   1.6  nathanw pthread_cond_wait_nothread(pthread_t self, pthread_mutex_t *mutex,
    399   1.6  nathanw     const struct timespec *abstime)
    400   1.6  nathanw {
    401  1.18  mycroft 	struct timespec now, diff;
    402   1.6  nathanw 	int retval;
    403   1.6  nathanw 
    404  1.18  mycroft 	if (abstime == NULL) {
    405  1.18  mycroft 		diff.tv_sec = 99999999;
    406  1.18  mycroft 		diff.tv_nsec = 0;
    407  1.18  mycroft 	} else {
    408  1.18  mycroft 		clock_gettime(CLOCK_REALTIME, &now);
    409  1.18  mycroft 		if  (timespeccmp(abstime, &now, <))
    410  1.18  mycroft 			timespecclear(&diff);
    411  1.17  nathanw 		else
    412  1.18  mycroft 			timespecsub(abstime, &now, &diff);
    413   1.6  nathanw 	}
    414   1.6  nathanw 
    415  1.18  mycroft 	do {
    416  1.18  mycroft 		pthread__testcancel(self);
    417  1.18  mycroft 		pthread_mutex_unlock(mutex);
    418  1.18  mycroft 		retval = _sys_nanosleep(&diff, NULL);
    419  1.18  mycroft 		pthread_mutex_lock(mutex);
    420  1.18  mycroft 	} while (abstime == NULL && retval == 0);
    421   1.6  nathanw 	pthread__testcancel(self);
    422   1.6  nathanw 
    423   1.6  nathanw 	if (retval == 0)
    424   1.6  nathanw 		return ETIMEDOUT;
    425   1.6  nathanw 	else
    426  1.15   kleink 		/* spurious wakeup */
    427  1.15   kleink 		return 0;
    428   1.2  thorpej }
    429