Home | History | Annotate | Line # | Download | only in libpthread
pthread_cond.c revision 1.1.2.7
      1 /*	$NetBSD: pthread_cond.c,v 1.1.2.7 2002/03/25 03:46:01 nathanw Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2001 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.
      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  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <assert.h>
     40 #include <errno.h>
     41 #include <sys/cdefs.h>
     42 
     43 #include "pthread.h"
     44 #include "pthread_int.h"
     45 
     46 static void pthread_cond_wait__callback(void *);
     47 
     48 /* Aliases for use by libc */
     49 __weak_alias(_libc_pthread_cond_init, pthread_cond_init)
     50 __weak_alias(_libc_pthread_cond_wait, pthread_cond_wait)
     51 __weak_alias(_libc_pthread_cond_signal, pthread_cond_signal)
     52 
     53 int
     54 pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
     55 {
     56 
     57 #ifdef ERRORCHECK
     58 	if ((cond == NULL) ||
     59 	    (attr && (attr->ptca_magic != _PT_CONDATTR_MAGIC)))
     60 		return EINVAL;
     61 #endif
     62 
     63 	cond->ptc_magic = _PT_COND_MAGIC;
     64 	pthread_lockinit(&cond->ptc_lock);
     65 	PTQ_INIT(&cond->ptc_waiters);
     66 	cond->ptc_mutex = NULL;
     67 
     68 	return 0;
     69 }
     70 
     71 
     72 int
     73 pthread_cond_destroy(pthread_cond_t *cond)
     74 {
     75 
     76 #ifdef ERRORCHECK
     77 	if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC) ||
     78 	    (cond->ptc_mutex != NULL) ||
     79 	    (cond->ptc_lock != __SIMPLELOCK_UNLOCKED))
     80 		return EINVAL;
     81 #endif
     82 
     83 	cond->ptc_magic = _PT_COND_DEAD;
     84 
     85 	return 0;
     86 }
     87 
     88 
     89 int
     90 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
     91 {
     92 	pthread_t self;
     93 #ifdef ERRORCHECK
     94 	if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC) ||
     95 	    (mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
     96 		return EINVAL;
     97 #endif
     98 
     99 	self = pthread__self();
    100 	pthread_spinlock(self, &cond->ptc_lock);
    101 	if (cond->ptc_mutex == NULL)
    102 		cond->ptc_mutex = mutex;
    103 	else
    104 		if (cond->ptc_mutex != mutex) {
    105 			pthread_spinunlock(self, &cond->ptc_lock);
    106 			return EINVAL;
    107 		}
    108 	pthread_spinlock(self, &self->pt_statelock);
    109 	if (self->pt_cancel) {
    110 		pthread_spinunlock(self, &self->pt_statelock);
    111 		pthread_spinunlock(self, &cond->ptc_lock);
    112 		pthread_exit(PTHREAD_CANCELED);
    113 	}
    114 	self->pt_state = PT_STATE_BLOCKED_QUEUE;
    115 	self->pt_sleepq = &cond->ptc_waiters;
    116 	self->pt_sleeplock = &cond->ptc_lock;
    117 	pthread_spinunlock(self, &self->pt_statelock);
    118 
    119 	PTQ_INSERT_TAIL(&cond->ptc_waiters, self, pt_sleep);
    120 	pthread_mutex_unlock(mutex);
    121 
    122 	pthread__block(self, &cond->ptc_lock);
    123 	/* Spinlock is unlocked on return */
    124 	pthread_mutex_lock(mutex);
    125 	pthread__testcancel(self);
    126 
    127 	return 0;
    128 }
    129 
    130 
    131 struct pthread_cond__waitarg {
    132 	pthread_t ptw_thread;
    133 	pthread_cond_t *ptw_cond;
    134 };
    135 
    136 int
    137 pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
    138     const struct timespec *abstime)
    139 {
    140 	pthread_t self;
    141 	struct pthread_cond__waitarg wait;
    142 	int retval;
    143 	void *alarm;
    144 
    145 #ifdef ERRORCHECK
    146 	if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC) ||
    147 	    (mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
    148 		return EINVAL;
    149 #endif
    150 
    151 	self = pthread__self();
    152 	pthread_spinlock(self, &cond->ptc_lock);
    153 	if (cond->ptc_mutex == NULL)
    154 		cond->ptc_mutex = mutex;
    155 	else
    156 		if (cond->ptc_mutex != mutex) {
    157 			pthread_spinunlock(self, &cond->ptc_lock);
    158 			return EINVAL;
    159 		}
    160 
    161 	wait.ptw_thread = self;
    162 	wait.ptw_cond = cond;
    163 	retval = 0;
    164 
    165 	pthread_spinlock(self, &self->pt_statelock);
    166 	if (self->pt_cancel) {
    167 		pthread_spinunlock(self, &self->pt_statelock);
    168 		pthread_spinunlock(self, &cond->ptc_lock);
    169 		pthread_exit(PTHREAD_CANCELED);
    170 	}
    171 	alarm = pthread__alarm_add(self, abstime, pthread_cond_wait__callback,
    172 	    &wait);
    173 	self->pt_state = PT_STATE_BLOCKED_QUEUE;
    174 	self->pt_sleepq = &cond->ptc_waiters;
    175 	self->pt_sleeplock = &cond->ptc_lock;
    176 	pthread_spinunlock(self, &self->pt_statelock);
    177 
    178 	PTQ_INSERT_TAIL(&cond->ptc_waiters, self, pt_sleep);
    179 	pthread_mutex_unlock(mutex);
    180 
    181 	pthread__block(self, &cond->ptc_lock);
    182 	/* Spinlock is unlocked on return */
    183 	if (pthread__alarm_fired(alarm))
    184 		retval = ETIMEDOUT;
    185 	pthread__alarm_del(self, alarm);
    186 	pthread_mutex_lock(mutex);
    187 	pthread__testcancel(self);
    188 
    189 	return retval;
    190 }
    191 
    192 static void
    193 pthread_cond_wait__callback(void *arg)
    194 {
    195 	struct pthread_cond__waitarg *a;
    196 	pthread_t self;
    197 
    198 	a = arg;
    199 	self = pthread__self();
    200 	pthread_spinlock(self, &a->ptw_cond->ptc_lock);
    201 	PTQ_REMOVE(&a->ptw_cond->ptc_waiters, a->ptw_thread, pt_sleep);
    202 	pthread_spinunlock(self, &a->ptw_cond->ptc_lock);
    203 	pthread__sched(self, a->ptw_thread);
    204 }
    205 
    206 int
    207 pthread_cond_signal(pthread_cond_t *cond)
    208 {
    209 	pthread_t self, signaled;
    210 #ifdef ERRORCHECK
    211 	if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC))
    212 		return EINVAL;
    213 #endif
    214 
    215 	self = pthread__self();
    216 
    217 	pthread_spinlock(self, &cond->ptc_lock);
    218 	signaled = PTQ_FIRST(&cond->ptc_waiters);
    219 	if (signaled != NULL)
    220 		PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
    221 	if (PTQ_EMPTY(&cond->ptc_waiters))
    222 		cond->ptc_mutex = NULL;
    223 	pthread_spinunlock(self, &cond->ptc_lock);
    224 
    225 	if (signaled != NULL)
    226 		pthread__sched(self, signaled);
    227 
    228 	return 0;
    229 }
    230 
    231 
    232 int
    233 pthread_cond_broadcast(pthread_cond_t *cond)
    234 {
    235 	pthread_t self, signaled;
    236 	struct pthread_queue_t blockedq, nullq = PTQ_HEAD_INITIALIZER;
    237 #ifdef ERRORCHECK
    238 	if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC))
    239 		return EINVAL;
    240 #endif
    241 
    242 	self = pthread__self();
    243 
    244 	pthread_spinlock(self, &cond->ptc_lock);
    245 	blockedq = cond->ptc_waiters;
    246 	cond->ptc_waiters = nullq;
    247 	cond->ptc_mutex = NULL;
    248 	pthread_spinunlock(self, &cond->ptc_lock);
    249 
    250 	PTQ_FOREACH(signaled, &blockedq, pt_sleep)
    251 	    pthread__sched(self, signaled);
    252 
    253 	return 0;
    254 
    255 }
    256 
    257 
    258 int
    259 pthread_condattr_init(pthread_condattr_t *attr)
    260 {
    261 
    262 #ifdef ERRORCHECK
    263 	if (attr == NULL)
    264 		return EINVAL;
    265 #endif
    266 
    267 	attr->ptca_magic = _PT_CONDATTR_MAGIC;
    268 
    269 	return 0;
    270 }
    271 
    272 
    273 int
    274 pthread_condattr_destroy(pthread_condattr_t *attr)
    275 {
    276 
    277 #ifdef ERRORCHECK
    278 	if ((attr == NULL) ||
    279 	    (attr->ptca_magic != _PT_CONDATTR_MAGIC))
    280 		return EINVAL;
    281 #endif
    282 
    283 	attr->ptca_magic = _PT_CONDATTR_DEAD;
    284 
    285 	return 0;
    286 }
    287