Home | History | Annotate | Line # | Download | only in libpthread
pthread_cond.c revision 1.1.2.6
      1 /*	$NetBSD: pthread_cond.c,v 1.1.2.6 2002/01/28 19:03:09 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 
     42 #include "pthread.h"
     43 #include "pthread_int.h"
     44 
     45 static void pthread_cond_wait__callback(void *);
     46 
     47 
     48 int
     49 pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr)
     50 {
     51 
     52 #ifdef ERRORCHECK
     53 	if ((cond == NULL) ||
     54 	    (attr && (attr->ptca_magic != _PT_CONDATTR_MAGIC)))
     55 		return EINVAL;
     56 #endif
     57 
     58 	cond->ptc_magic = _PT_COND_MAGIC;
     59 	pthread_lockinit(&cond->ptc_lock);
     60 	PTQ_INIT(&cond->ptc_waiters);
     61 	cond->ptc_mutex = NULL;
     62 
     63 	return 0;
     64 }
     65 
     66 
     67 int
     68 pthread_cond_destroy(pthread_cond_t *cond)
     69 {
     70 
     71 #ifdef ERRORCHECK
     72 	if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC) ||
     73 	    (cond->ptc_mutex != NULL) ||
     74 	    (cond->ptc_lock != __SIMPLELOCK_UNLOCKED))
     75 		return EINVAL;
     76 #endif
     77 
     78 	cond->ptc_magic = _PT_COND_DEAD;
     79 
     80 	return 0;
     81 }
     82 
     83 
     84 int
     85 pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
     86 {
     87 	pthread_t self;
     88 #ifdef ERRORCHECK
     89 	if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC) ||
     90 	    (mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
     91 		return EINVAL;
     92 #endif
     93 
     94 	self = pthread__self();
     95 	pthread_spinlock(self, &cond->ptc_lock);
     96 	if (cond->ptc_mutex == NULL)
     97 		cond->ptc_mutex = mutex;
     98 	else
     99 		if (cond->ptc_mutex != mutex) {
    100 			pthread_spinunlock(self, &cond->ptc_lock);
    101 			return EINVAL;
    102 		}
    103 	pthread_spinlock(self, &self->pt_statelock);
    104 	if (self->pt_cancel) {
    105 		pthread_spinunlock(self, &self->pt_statelock);
    106 		pthread_spinunlock(self, &cond->ptc_lock);
    107 		pthread_exit(PTHREAD_CANCELED);
    108 	}
    109 	self->pt_state = PT_STATE_BLOCKED_QUEUE;
    110 	self->pt_sleepq = &cond->ptc_waiters;
    111 	self->pt_sleeplock = &cond->ptc_lock;
    112 	pthread_spinunlock(self, &self->pt_statelock);
    113 
    114 	PTQ_INSERT_TAIL(&cond->ptc_waiters, self, pt_sleep);
    115 	pthread_mutex_unlock(mutex);
    116 
    117 	pthread__block(self, &cond->ptc_lock);
    118 	/* Spinlock is unlocked on return */
    119 	pthread_mutex_lock(mutex);
    120 	pthread__testcancel(self);
    121 
    122 	return 0;
    123 }
    124 
    125 
    126 struct pthread_cond__waitarg {
    127 	pthread_t ptw_thread;
    128 	pthread_cond_t *ptw_cond;
    129 };
    130 
    131 int
    132 pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
    133     const struct timespec *abstime)
    134 {
    135 	pthread_t self;
    136 	struct pthread_cond__waitarg wait;
    137 	int retval;
    138 	void *alarm;
    139 
    140 #ifdef ERRORCHECK
    141 	if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC) ||
    142 	    (mutex == NULL) || (mutex->ptm_magic != _PT_MUTEX_MAGIC))
    143 		return EINVAL;
    144 #endif
    145 
    146 	self = pthread__self();
    147 	pthread_spinlock(self, &cond->ptc_lock);
    148 	if (cond->ptc_mutex == NULL)
    149 		cond->ptc_mutex = mutex;
    150 	else
    151 		if (cond->ptc_mutex != mutex) {
    152 			pthread_spinunlock(self, &cond->ptc_lock);
    153 			return EINVAL;
    154 		}
    155 
    156 	wait.ptw_thread = self;
    157 	wait.ptw_cond = cond;
    158 	retval = 0;
    159 
    160 	pthread_spinlock(self, &self->pt_statelock);
    161 	if (self->pt_cancel) {
    162 		pthread_spinunlock(self, &self->pt_statelock);
    163 		pthread_spinunlock(self, &cond->ptc_lock);
    164 		pthread_exit(PTHREAD_CANCELED);
    165 	}
    166 	alarm = pthread__alarm_add(self, abstime, pthread_cond_wait__callback,
    167 	    &wait);
    168 	self->pt_state = PT_STATE_BLOCKED_QUEUE;
    169 	self->pt_sleepq = &cond->ptc_waiters;
    170 	self->pt_sleeplock = &cond->ptc_lock;
    171 	pthread_spinunlock(self, &self->pt_statelock);
    172 
    173 	PTQ_INSERT_TAIL(&cond->ptc_waiters, self, pt_sleep);
    174 	pthread_mutex_unlock(mutex);
    175 
    176 	pthread__block(self, &cond->ptc_lock);
    177 	/* Spinlock is unlocked on return */
    178 	if (pthread__alarm_fired(alarm))
    179 		retval = ETIMEDOUT;
    180 	pthread__alarm_del(self, alarm);
    181 	pthread_mutex_lock(mutex);
    182 	pthread__testcancel(self);
    183 
    184 	return retval;
    185 }
    186 
    187 static void
    188 pthread_cond_wait__callback(void *arg)
    189 {
    190 	struct pthread_cond__waitarg *a;
    191 	pthread_t self;
    192 
    193 	a = arg;
    194 	self = pthread__self();
    195 	pthread_spinlock(self, &a->ptw_cond->ptc_lock);
    196 	PTQ_REMOVE(&a->ptw_cond->ptc_waiters, a->ptw_thread, pt_sleep);
    197 	pthread_spinunlock(self, &a->ptw_cond->ptc_lock);
    198 	pthread__sched(self, a->ptw_thread);
    199 }
    200 
    201 int
    202 pthread_cond_signal(pthread_cond_t *cond)
    203 {
    204 	pthread_t self, signaled;
    205 #ifdef ERRORCHECK
    206 	if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC))
    207 		return EINVAL;
    208 #endif
    209 
    210 	self = pthread__self();
    211 
    212 	pthread_spinlock(self, &cond->ptc_lock);
    213 	signaled = PTQ_FIRST(&cond->ptc_waiters);
    214 	if (signaled != NULL)
    215 		PTQ_REMOVE(&cond->ptc_waiters, signaled, pt_sleep);
    216 	if (PTQ_EMPTY(&cond->ptc_waiters))
    217 		cond->ptc_mutex = NULL;
    218 	pthread_spinunlock(self, &cond->ptc_lock);
    219 
    220 	if (signaled != NULL)
    221 		pthread__sched(self, signaled);
    222 
    223 	return 0;
    224 }
    225 
    226 
    227 int
    228 pthread_cond_broadcast(pthread_cond_t *cond)
    229 {
    230 	pthread_t self, signaled;
    231 	struct pthread_queue_t blockedq, nullq = PTQ_HEAD_INITIALIZER;
    232 #ifdef ERRORCHECK
    233 	if ((cond == NULL) || (cond->ptc_magic != _PT_COND_MAGIC))
    234 		return EINVAL;
    235 #endif
    236 
    237 	self = pthread__self();
    238 
    239 	pthread_spinlock(self, &cond->ptc_lock);
    240 	blockedq = cond->ptc_waiters;
    241 	cond->ptc_waiters = nullq;
    242 	cond->ptc_mutex = NULL;
    243 	pthread_spinunlock(self, &cond->ptc_lock);
    244 
    245 	PTQ_FOREACH(signaled, &blockedq, pt_sleep)
    246 	    pthread__sched(self, signaled);
    247 
    248 	return 0;
    249 
    250 }
    251 
    252 
    253 int
    254 pthread_condattr_init(pthread_condattr_t *attr)
    255 {
    256 
    257 #ifdef ERRORCHECK
    258 	if (attr == NULL)
    259 		return EINVAL;
    260 #endif
    261 
    262 	attr->ptca_magic = _PT_CONDATTR_MAGIC;
    263 
    264 	return 0;
    265 }
    266 
    267 
    268 int
    269 pthread_condattr_destroy(pthread_condattr_t *attr)
    270 {
    271 
    272 #ifdef ERRORCHECK
    273 	if ((attr == NULL) ||
    274 	    (attr->ptca_magic != _PT_CONDATTR_MAGIC))
    275 		return EINVAL;
    276 #endif
    277 
    278 	attr->ptca_magic = _PT_CONDATTR_DEAD;
    279 
    280 	return 0;
    281 }
    282