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