Home | History | Annotate | Line # | Download | only in libpthread
pthread_rwlock.c revision 1.1.2.1
      1  1.1.2.1  nathanw /*	$NetBSD: pthread_rwlock.c,v 1.1.2.1 2002/10/28 00:06:09 nathanw Exp $ */
      2  1.1.2.1  nathanw 
      3  1.1.2.1  nathanw /*-
      4  1.1.2.1  nathanw  * Copyright (c) 2002 The NetBSD Foundation, Inc.
      5  1.1.2.1  nathanw  * All rights reserved.
      6  1.1.2.1  nathanw  *
      7  1.1.2.1  nathanw  * This code is derived from software contributed to The NetBSD Foundation
      8  1.1.2.1  nathanw  * by Nathan J. Williams.
      9  1.1.2.1  nathanw  *
     10  1.1.2.1  nathanw  * Redistribution and use in source and binary forms, with or without
     11  1.1.2.1  nathanw  * modification, are permitted provided that the following conditions
     12  1.1.2.1  nathanw  * are met:
     13  1.1.2.1  nathanw  * 1. Redistributions of source code must retain the above copyright
     14  1.1.2.1  nathanw  *    notice, this list of conditions and the following disclaimer.
     15  1.1.2.1  nathanw  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.1.2.1  nathanw  *    notice, this list of conditions and the following disclaimer in the
     17  1.1.2.1  nathanw  *    documentation and/or other materials provided with the distribution.
     18  1.1.2.1  nathanw  * 3. All advertising materials mentioning features or use of this software
     19  1.1.2.1  nathanw  *    must display the following acknowledgement:
     20  1.1.2.1  nathanw  *        This product includes software developed by the NetBSD
     21  1.1.2.1  nathanw  *        Foundation, Inc. and its contributors.
     22  1.1.2.1  nathanw  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  1.1.2.1  nathanw  *    contributors may be used to endorse or promote products derived
     24  1.1.2.1  nathanw  *    from this software without specific prior written permission.
     25  1.1.2.1  nathanw  *
     26  1.1.2.1  nathanw  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  1.1.2.1  nathanw  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  1.1.2.1  nathanw  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  1.1.2.1  nathanw  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  1.1.2.1  nathanw  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  1.1.2.1  nathanw  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  1.1.2.1  nathanw  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  1.1.2.1  nathanw  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  1.1.2.1  nathanw  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  1.1.2.1  nathanw  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  1.1.2.1  nathanw  * POSSIBILITY OF SUCH DAMAGE.
     37  1.1.2.1  nathanw  */
     38  1.1.2.1  nathanw 
     39  1.1.2.1  nathanw #include <assert.h>
     40  1.1.2.1  nathanw #include <errno.h>
     41  1.1.2.1  nathanw #include <sys/cdefs.h>
     42  1.1.2.1  nathanw 
     43  1.1.2.1  nathanw #include "pthread.h"
     44  1.1.2.1  nathanw #include "pthread_int.h"
     45  1.1.2.1  nathanw 
     46  1.1.2.1  nathanw static void pthread_rwlock__callback(void *);
     47  1.1.2.1  nathanw 
     48  1.1.2.1  nathanw int
     49  1.1.2.1  nathanw pthread_rwlock_init(pthread_rwlock_t *rwlock,
     50  1.1.2.1  nathanw 	    const pthread_rwlockattr_t *attr)
     51  1.1.2.1  nathanw {
     52  1.1.2.1  nathanw #ifdef ERRORCHECK
     53  1.1.2.1  nathanw 	if ((rwlock == NULL) ||
     54  1.1.2.1  nathanw 	    (attr && (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC)))
     55  1.1.2.1  nathanw 		return EINVAL;
     56  1.1.2.1  nathanw #endif
     57  1.1.2.1  nathanw 	rwlock->ptr_magic = _PT_RWLOCK_MAGIC;
     58  1.1.2.1  nathanw 	pthread_lockinit(&rwlock->ptr_interlock);
     59  1.1.2.1  nathanw 	PTQ_INIT(&rwlock->ptr_rblocked);
     60  1.1.2.1  nathanw 	PTQ_INIT(&rwlock->ptr_wblocked);
     61  1.1.2.1  nathanw 	rwlock->ptr_nreaders = 0;
     62  1.1.2.1  nathanw 	rwlock->ptr_writer = NULL;
     63  1.1.2.1  nathanw 
     64  1.1.2.1  nathanw 	return 0;
     65  1.1.2.1  nathanw }
     66  1.1.2.1  nathanw 
     67  1.1.2.1  nathanw 
     68  1.1.2.1  nathanw int
     69  1.1.2.1  nathanw pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
     70  1.1.2.1  nathanw {
     71  1.1.2.1  nathanw #ifdef ERRORCHECK
     72  1.1.2.1  nathanw 	if ((rwlock == NULL) ||
     73  1.1.2.1  nathanw 	    (rwlock->ptr_magic != _PT_RWLOCK_MAGIC) ||
     74  1.1.2.1  nathanw 	    (!PTQ_EMPTY(&rwlock->ptr_rblocked)) ||
     75  1.1.2.1  nathanw 	    (!PTQ_EMPTY(&rwlock->ptr_wblocked)) ||
     76  1.1.2.1  nathanw 	    (rwlock->ptr_nreaders != 0) ||
     77  1.1.2.1  nathanw 	    (rwlock->ptr_writer != NULL))
     78  1.1.2.1  nathanw 		return EINVAL;
     79  1.1.2.1  nathanw #endif
     80  1.1.2.1  nathanw 	rwlock->ptr_magic = _PT_RWLOCK_DEAD;
     81  1.1.2.1  nathanw 
     82  1.1.2.1  nathanw 	return 0;
     83  1.1.2.1  nathanw }
     84  1.1.2.1  nathanw 
     85  1.1.2.1  nathanw 
     86  1.1.2.1  nathanw int
     87  1.1.2.1  nathanw pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
     88  1.1.2.1  nathanw {
     89  1.1.2.1  nathanw 	pthread_t self;
     90  1.1.2.1  nathanw #ifdef ERRORCHECK
     91  1.1.2.1  nathanw 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
     92  1.1.2.1  nathanw 		return EINVAL;
     93  1.1.2.1  nathanw #endif
     94  1.1.2.1  nathanw 	self = pthread__self();
     95  1.1.2.1  nathanw 
     96  1.1.2.1  nathanw 	pthread_spinlock(self, &rwlock->ptr_interlock);
     97  1.1.2.1  nathanw #ifdef ERRORCHECK
     98  1.1.2.1  nathanw 	if (rwlock->ptr_writer == self) {
     99  1.1.2.1  nathanw 		pthread_spinunlock(self, &rwlock->ptr_interlock);
    100  1.1.2.1  nathanw 		return EDEADLK;
    101  1.1.2.1  nathanw 	}
    102  1.1.2.1  nathanw #endif
    103  1.1.2.1  nathanw 	/*
    104  1.1.2.1  nathanw 	 * Don't get a readlock if there is a writer or if there are waiting
    105  1.1.2.1  nathanw 	 * writers; i.e. prefer writers to readers. This strategy is dictated
    106  1.1.2.1  nathanw 	 * by SUSv3.
    107  1.1.2.1  nathanw 	 */
    108  1.1.2.1  nathanw 	while ((rwlock->ptr_writer != NULL) ||
    109  1.1.2.1  nathanw 	    (!PTQ_EMPTY(&rwlock->ptr_wblocked))) {
    110  1.1.2.1  nathanw 		PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
    111  1.1.2.1  nathanw 		/* Locking a rwlock is not a cancellation point; don't check */
    112  1.1.2.1  nathanw 		pthread_spinlock(self, &self->pt_statelock);
    113  1.1.2.1  nathanw 		self->pt_state = PT_STATE_BLOCKED_QUEUE;
    114  1.1.2.1  nathanw 		self->pt_sleepobj = rwlock;
    115  1.1.2.1  nathanw 		self->pt_sleepq = &rwlock->ptr_rblocked;
    116  1.1.2.1  nathanw 		self->pt_sleeplock = &rwlock->ptr_interlock;
    117  1.1.2.1  nathanw 		pthread_spinunlock(self, &self->pt_statelock);
    118  1.1.2.1  nathanw 		pthread__block(self, &rwlock->ptr_interlock);
    119  1.1.2.1  nathanw 		/* interlock is not held when we return */
    120  1.1.2.1  nathanw 		pthread_spinlock(self, &rwlock->ptr_interlock);
    121  1.1.2.1  nathanw 	}
    122  1.1.2.1  nathanw 
    123  1.1.2.1  nathanw 	rwlock->ptr_nreaders++;
    124  1.1.2.1  nathanw 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    125  1.1.2.1  nathanw 
    126  1.1.2.1  nathanw 	return 0;
    127  1.1.2.1  nathanw }
    128  1.1.2.1  nathanw 
    129  1.1.2.1  nathanw 
    130  1.1.2.1  nathanw int
    131  1.1.2.1  nathanw pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
    132  1.1.2.1  nathanw {
    133  1.1.2.1  nathanw 	pthread_t self;
    134  1.1.2.1  nathanw #ifdef ERRORCHECK
    135  1.1.2.1  nathanw 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    136  1.1.2.1  nathanw 		return EINVAL;
    137  1.1.2.1  nathanw #endif
    138  1.1.2.1  nathanw 	self = pthread__self();
    139  1.1.2.1  nathanw 
    140  1.1.2.1  nathanw 	pthread_spinlock(self, &rwlock->ptr_interlock);
    141  1.1.2.1  nathanw #ifdef ERRORCHECK
    142  1.1.2.1  nathanw 	if (rwlock->ptr_writer == self) {
    143  1.1.2.1  nathanw 		pthread_spinunlock(self, &rwlock->ptr_interlock);
    144  1.1.2.1  nathanw 		return EDEADLK;
    145  1.1.2.1  nathanw 	}
    146  1.1.2.1  nathanw #endif
    147  1.1.2.1  nathanw 	/*
    148  1.1.2.1  nathanw 	 * Don't get a readlock if there is a writer or if there are waiting
    149  1.1.2.1  nathanw 	 * writers; i.e. prefer writers to readers. This strategy is dictated
    150  1.1.2.1  nathanw 	 * by SUSv3.
    151  1.1.2.1  nathanw 	 */
    152  1.1.2.1  nathanw 	if ((rwlock->ptr_writer != NULL) ||
    153  1.1.2.1  nathanw 	    (!PTQ_EMPTY(&rwlock->ptr_wblocked))) {
    154  1.1.2.1  nathanw 		pthread_spinunlock(self, &rwlock->ptr_interlock);
    155  1.1.2.1  nathanw 		return EBUSY;
    156  1.1.2.1  nathanw 	}
    157  1.1.2.1  nathanw 
    158  1.1.2.1  nathanw 	rwlock->ptr_nreaders++;
    159  1.1.2.1  nathanw 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    160  1.1.2.1  nathanw 
    161  1.1.2.1  nathanw 	return 0;
    162  1.1.2.1  nathanw }
    163  1.1.2.1  nathanw 
    164  1.1.2.1  nathanw 
    165  1.1.2.1  nathanw int
    166  1.1.2.1  nathanw pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
    167  1.1.2.1  nathanw {
    168  1.1.2.1  nathanw 	pthread_t self;
    169  1.1.2.1  nathanw #ifdef ERRORCHECK
    170  1.1.2.1  nathanw 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    171  1.1.2.1  nathanw 		return EINVAL;
    172  1.1.2.1  nathanw #endif
    173  1.1.2.1  nathanw 	self = pthread__self();
    174  1.1.2.1  nathanw 
    175  1.1.2.1  nathanw 	pthread_spinlock(self, &rwlock->ptr_interlock);
    176  1.1.2.1  nathanw 	/*
    177  1.1.2.1  nathanw 	 * Prefer writers to readers here; permit writers even if there are
    178  1.1.2.1  nathanw 	 * waiting readers.
    179  1.1.2.1  nathanw 	 */
    180  1.1.2.1  nathanw 	while ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
    181  1.1.2.1  nathanw 		PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
    182  1.1.2.1  nathanw 		/* Locking a rwlock is not a cancellation point; don't check */
    183  1.1.2.1  nathanw 		pthread_spinlock(self, &self->pt_statelock);
    184  1.1.2.1  nathanw 		self->pt_state = PT_STATE_BLOCKED_QUEUE;
    185  1.1.2.1  nathanw 		self->pt_sleepobj = rwlock;
    186  1.1.2.1  nathanw 		self->pt_sleepq = &rwlock->ptr_wblocked;
    187  1.1.2.1  nathanw 		self->pt_sleeplock = &rwlock->ptr_interlock;
    188  1.1.2.1  nathanw 		pthread_spinunlock(self, &self->pt_statelock);
    189  1.1.2.1  nathanw 		pthread__block(self, &rwlock->ptr_interlock);
    190  1.1.2.1  nathanw 		/* interlock is not held when we return */
    191  1.1.2.1  nathanw 		pthread_spinlock(self, &rwlock->ptr_interlock);
    192  1.1.2.1  nathanw 	}
    193  1.1.2.1  nathanw 
    194  1.1.2.1  nathanw 	rwlock->ptr_writer = self;
    195  1.1.2.1  nathanw 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    196  1.1.2.1  nathanw 
    197  1.1.2.1  nathanw 	return 0;
    198  1.1.2.1  nathanw }
    199  1.1.2.1  nathanw 
    200  1.1.2.1  nathanw 
    201  1.1.2.1  nathanw int
    202  1.1.2.1  nathanw pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
    203  1.1.2.1  nathanw {
    204  1.1.2.1  nathanw 	pthread_t self;
    205  1.1.2.1  nathanw #ifdef ERRORCHECK
    206  1.1.2.1  nathanw 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    207  1.1.2.1  nathanw 		return EINVAL;
    208  1.1.2.1  nathanw #endif
    209  1.1.2.1  nathanw 	self = pthread__self();
    210  1.1.2.1  nathanw 
    211  1.1.2.1  nathanw 	pthread_spinlock(self, &rwlock->ptr_interlock);
    212  1.1.2.1  nathanw 	/*
    213  1.1.2.1  nathanw 	 * Prefer writers to readers here; permit writers even if there are
    214  1.1.2.1  nathanw 	 * waiting readers.
    215  1.1.2.1  nathanw 	 */
    216  1.1.2.1  nathanw 	if ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
    217  1.1.2.1  nathanw 		pthread_spinunlock(self, &rwlock->ptr_interlock);
    218  1.1.2.1  nathanw 		return EBUSY;
    219  1.1.2.1  nathanw 	}
    220  1.1.2.1  nathanw 
    221  1.1.2.1  nathanw 	rwlock->ptr_writer = self;
    222  1.1.2.1  nathanw 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    223  1.1.2.1  nathanw 
    224  1.1.2.1  nathanw 	return 0;
    225  1.1.2.1  nathanw }
    226  1.1.2.1  nathanw 
    227  1.1.2.1  nathanw 
    228  1.1.2.1  nathanw struct pthread_rwlock__waitarg {
    229  1.1.2.1  nathanw 	pthread_t ptw_thread;
    230  1.1.2.1  nathanw 	pthread_rwlock_t *ptw_rwlock;
    231  1.1.2.1  nathanw 	struct pthread_queue_t *ptw_queue;
    232  1.1.2.1  nathanw };
    233  1.1.2.1  nathanw 
    234  1.1.2.1  nathanw int
    235  1.1.2.1  nathanw pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
    236  1.1.2.1  nathanw 	    const struct timespec *abs_timeout)
    237  1.1.2.1  nathanw {
    238  1.1.2.1  nathanw 	pthread_t self;
    239  1.1.2.1  nathanw 	struct pthread_rwlock__waitarg wait;
    240  1.1.2.1  nathanw 	struct pt_alarm_t alarm;
    241  1.1.2.1  nathanw 	int retval, armed;
    242  1.1.2.1  nathanw #ifdef ERRORCHECK
    243  1.1.2.1  nathanw 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    244  1.1.2.1  nathanw 		return EINVAL;
    245  1.1.2.1  nathanw #endif
    246  1.1.2.1  nathanw 	self = pthread__self();
    247  1.1.2.1  nathanw 
    248  1.1.2.1  nathanw 	pthread_spinlock(self, &rwlock->ptr_interlock);
    249  1.1.2.1  nathanw #ifdef ERRORCHECK
    250  1.1.2.1  nathanw 	if (rwlock->ptr_writer == self) {
    251  1.1.2.1  nathanw 		pthread_spinlock(self, &rwlock->ptr_interlock);
    252  1.1.2.1  nathanw 		return EDEADLK;
    253  1.1.2.1  nathanw 	}
    254  1.1.2.1  nathanw #endif
    255  1.1.2.1  nathanw 	/*
    256  1.1.2.1  nathanw 	 * Don't get a readlock if there is a writer or if there are waiting
    257  1.1.2.1  nathanw 	 * writers; i.e. prefer writers to readers. This strategy is dictated
    258  1.1.2.1  nathanw 	 * by SUSv3.
    259  1.1.2.1  nathanw 	 */
    260  1.1.2.1  nathanw 	retval = armed = 0;
    261  1.1.2.1  nathanw 	while ((retval == 0) && ((rwlock->ptr_writer != NULL) ||
    262  1.1.2.1  nathanw 	    (!PTQ_EMPTY(&rwlock->ptr_wblocked)))) {
    263  1.1.2.1  nathanw 		if (!armed) {
    264  1.1.2.1  nathanw 			armed = 1;
    265  1.1.2.1  nathanw 			wait.ptw_thread = self;
    266  1.1.2.1  nathanw 			wait.ptw_rwlock = rwlock;
    267  1.1.2.1  nathanw 			wait.ptw_queue = &rwlock->ptr_rblocked;
    268  1.1.2.1  nathanw 			pthread__alarm_add(self, &alarm, abs_timeout,
    269  1.1.2.1  nathanw 			    pthread_rwlock__callback, &wait);
    270  1.1.2.1  nathanw 		}
    271  1.1.2.1  nathanw 		PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
    272  1.1.2.1  nathanw 		/* Locking a rwlock is not a cancellation point; don't check */
    273  1.1.2.1  nathanw 		pthread_spinlock(self, &self->pt_statelock);
    274  1.1.2.1  nathanw 		self->pt_state = PT_STATE_BLOCKED_QUEUE;
    275  1.1.2.1  nathanw 		self->pt_sleepobj = rwlock;
    276  1.1.2.1  nathanw 		self->pt_sleepq = &rwlock->ptr_rblocked;
    277  1.1.2.1  nathanw 		self->pt_sleeplock = &rwlock->ptr_interlock;
    278  1.1.2.1  nathanw 		pthread_spinunlock(self, &self->pt_statelock);
    279  1.1.2.1  nathanw 		pthread__block(self, &rwlock->ptr_interlock);
    280  1.1.2.1  nathanw 		/* interlock is not held when we return */
    281  1.1.2.1  nathanw 		if (pthread__alarm_fired(&alarm))
    282  1.1.2.1  nathanw 			retval = ETIMEDOUT;
    283  1.1.2.1  nathanw 		pthread_spinlock(self, &rwlock->ptr_interlock);
    284  1.1.2.1  nathanw 	}
    285  1.1.2.1  nathanw 
    286  1.1.2.1  nathanw 	if (retval == 0)
    287  1.1.2.1  nathanw 		rwlock->ptr_nreaders++;
    288  1.1.2.1  nathanw 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    289  1.1.2.1  nathanw 	if (armed)
    290  1.1.2.1  nathanw 		pthread__alarm_del(self, &alarm);
    291  1.1.2.1  nathanw 
    292  1.1.2.1  nathanw 	return retval;
    293  1.1.2.1  nathanw }
    294  1.1.2.1  nathanw 
    295  1.1.2.1  nathanw 
    296  1.1.2.1  nathanw int
    297  1.1.2.1  nathanw pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock,
    298  1.1.2.1  nathanw 	    const struct timespec *abs_timeout)
    299  1.1.2.1  nathanw {
    300  1.1.2.1  nathanw 	struct pthread_rwlock__waitarg wait;
    301  1.1.2.1  nathanw 	struct pt_alarm_t alarm;
    302  1.1.2.1  nathanw 	int retval, armed;
    303  1.1.2.1  nathanw 	pthread_t self;
    304  1.1.2.1  nathanw #ifdef ERRORCHECK
    305  1.1.2.1  nathanw 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    306  1.1.2.1  nathanw 		return EINVAL;
    307  1.1.2.1  nathanw #endif
    308  1.1.2.1  nathanw 	self = pthread__self();
    309  1.1.2.1  nathanw 
    310  1.1.2.1  nathanw 	pthread_spinlock(self, &rwlock->ptr_interlock);
    311  1.1.2.1  nathanw 	/*
    312  1.1.2.1  nathanw 	 * Prefer writers to readers here; permit writers even if there are
    313  1.1.2.1  nathanw 	 * waiting readers.
    314  1.1.2.1  nathanw 	 */
    315  1.1.2.1  nathanw 	retval = armed = 0;
    316  1.1.2.1  nathanw 	while (retval == 0 &&
    317  1.1.2.1  nathanw 	    ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL))) {
    318  1.1.2.1  nathanw 		if (armed == 0) {
    319  1.1.2.1  nathanw 			armed = 1;
    320  1.1.2.1  nathanw 			wait.ptw_thread = self;
    321  1.1.2.1  nathanw 			wait.ptw_rwlock = rwlock;
    322  1.1.2.1  nathanw 			wait.ptw_queue = &rwlock->ptr_wblocked;
    323  1.1.2.1  nathanw 			pthread__alarm_add(self, &alarm, abs_timeout,
    324  1.1.2.1  nathanw 			    pthread_rwlock__callback, &wait);
    325  1.1.2.1  nathanw 		}
    326  1.1.2.1  nathanw 		PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
    327  1.1.2.1  nathanw 		/* Locking a rwlock is not a cancellation point; don't check */
    328  1.1.2.1  nathanw 		pthread_spinlock(self, &self->pt_statelock);
    329  1.1.2.1  nathanw 		self->pt_state = PT_STATE_BLOCKED_QUEUE;
    330  1.1.2.1  nathanw 		self->pt_sleepobj = rwlock;
    331  1.1.2.1  nathanw 		self->pt_sleepq = &rwlock->ptr_wblocked;
    332  1.1.2.1  nathanw 		self->pt_sleeplock = &rwlock->ptr_interlock;
    333  1.1.2.1  nathanw 		pthread_spinunlock(self, &self->pt_statelock);
    334  1.1.2.1  nathanw 		pthread__block(self, &rwlock->ptr_interlock);
    335  1.1.2.1  nathanw 		/* interlock is not held when we return */
    336  1.1.2.1  nathanw 		if (pthread__alarm_fired(&alarm))
    337  1.1.2.1  nathanw 			retval = ETIMEDOUT;
    338  1.1.2.1  nathanw 		pthread_spinlock(self, &rwlock->ptr_interlock);
    339  1.1.2.1  nathanw 	}
    340  1.1.2.1  nathanw 
    341  1.1.2.1  nathanw 	if (retval == 0)
    342  1.1.2.1  nathanw 		rwlock->ptr_writer = self;
    343  1.1.2.1  nathanw 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    344  1.1.2.1  nathanw 	if (armed)
    345  1.1.2.1  nathanw 		pthread__alarm_del(self, &alarm);
    346  1.1.2.1  nathanw 
    347  1.1.2.1  nathanw 	return 0;
    348  1.1.2.1  nathanw }
    349  1.1.2.1  nathanw 
    350  1.1.2.1  nathanw 
    351  1.1.2.1  nathanw static void
    352  1.1.2.1  nathanw pthread_rwlock__callback(void *arg)
    353  1.1.2.1  nathanw {
    354  1.1.2.1  nathanw 	struct pthread_rwlock__waitarg *a;
    355  1.1.2.1  nathanw 	pthread_t self;
    356  1.1.2.1  nathanw 
    357  1.1.2.1  nathanw 	a = arg;
    358  1.1.2.1  nathanw 	self = pthread__self();
    359  1.1.2.1  nathanw 
    360  1.1.2.1  nathanw 	pthread_spinlock(self, &a->ptw_rwlock->ptr_interlock);
    361  1.1.2.1  nathanw 	PTQ_REMOVE(a->ptw_queue, a->ptw_thread, pt_sleep);
    362  1.1.2.1  nathanw 	pthread_spinunlock(self, &a->ptw_rwlock->ptr_interlock);
    363  1.1.2.1  nathanw 	pthread__sched(self, a->ptw_thread);
    364  1.1.2.1  nathanw }
    365  1.1.2.1  nathanw 
    366  1.1.2.1  nathanw 
    367  1.1.2.1  nathanw int
    368  1.1.2.1  nathanw pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
    369  1.1.2.1  nathanw {
    370  1.1.2.1  nathanw 	pthread_t self, reader, writer;
    371  1.1.2.1  nathanw 	struct pthread_queue_t blockedq;
    372  1.1.2.1  nathanw #ifdef ERRORCHECK
    373  1.1.2.1  nathanw 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    374  1.1.2.1  nathanw 		return EINVAL;
    375  1.1.2.1  nathanw #endif
    376  1.1.2.1  nathanw 	writer = NULL;
    377  1.1.2.1  nathanw 	PTQ_INIT(&blockedq);
    378  1.1.2.1  nathanw 	self = pthread__self();
    379  1.1.2.1  nathanw 
    380  1.1.2.1  nathanw 	pthread_spinlock(self, &rwlock->ptr_interlock);
    381  1.1.2.1  nathanw 	if (rwlock->ptr_writer != NULL) {
    382  1.1.2.1  nathanw 		/* Releasing a write lock. */
    383  1.1.2.1  nathanw #ifdef ERRORCHECK
    384  1.1.2.1  nathanw 		if (rwlock->ptr_writer != self) {
    385  1.1.2.1  nathanw 			pthread_spinunlock(self, &rwlock->ptr_interlock);
    386  1.1.2.1  nathanw 			return EPERM;
    387  1.1.2.1  nathanw 		}
    388  1.1.2.1  nathanw #endif
    389  1.1.2.1  nathanw 		rwlock->ptr_writer = NULL;
    390  1.1.2.1  nathanw 		writer = PTQ_FIRST(&rwlock->ptr_wblocked);
    391  1.1.2.1  nathanw 		if (writer != NULL) {
    392  1.1.2.1  nathanw 			PTQ_REMOVE(&rwlock->ptr_wblocked, writer, pt_sleep);
    393  1.1.2.1  nathanw 		} else {
    394  1.1.2.1  nathanw 			blockedq = rwlock->ptr_rblocked;
    395  1.1.2.1  nathanw 			PTQ_INIT(&rwlock->ptr_rblocked);
    396  1.1.2.1  nathanw 		}
    397  1.1.2.1  nathanw 	} else {
    398  1.1.2.1  nathanw 		/* Releasing a read lock. */
    399  1.1.2.1  nathanw 		rwlock->ptr_nreaders--;
    400  1.1.2.1  nathanw 		if (rwlock->ptr_nreaders == 0) {
    401  1.1.2.1  nathanw 			writer = PTQ_FIRST(&rwlock->ptr_wblocked);
    402  1.1.2.1  nathanw 			if (writer != NULL)
    403  1.1.2.1  nathanw 				PTQ_REMOVE(&rwlock->ptr_wblocked, writer,
    404  1.1.2.1  nathanw 				    pt_sleep);
    405  1.1.2.1  nathanw 		}
    406  1.1.2.1  nathanw 	}
    407  1.1.2.1  nathanw 
    408  1.1.2.1  nathanw 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    409  1.1.2.1  nathanw 
    410  1.1.2.1  nathanw 	if (writer != NULL)
    411  1.1.2.1  nathanw 		pthread__sched(self, writer);
    412  1.1.2.1  nathanw 	else
    413  1.1.2.1  nathanw 		PTQ_FOREACH(reader, &blockedq, pt_sleep)
    414  1.1.2.1  nathanw 			pthread__sched(self, reader);
    415  1.1.2.1  nathanw 
    416  1.1.2.1  nathanw 	return 0;
    417  1.1.2.1  nathanw }
    418  1.1.2.1  nathanw 
    419  1.1.2.1  nathanw 
    420  1.1.2.1  nathanw int
    421  1.1.2.1  nathanw pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
    422  1.1.2.1  nathanw {
    423  1.1.2.1  nathanw #ifdef ERRORCHECK
    424  1.1.2.1  nathanw 	if (attr == NULL)
    425  1.1.2.1  nathanw 		return EINVAL;
    426  1.1.2.1  nathanw #endif
    427  1.1.2.1  nathanw 	attr->ptra_magic = _PT_RWLOCKATTR_MAGIC;
    428  1.1.2.1  nathanw 
    429  1.1.2.1  nathanw 	return 0;
    430  1.1.2.1  nathanw }
    431  1.1.2.1  nathanw 
    432  1.1.2.1  nathanw 
    433  1.1.2.1  nathanw int
    434  1.1.2.1  nathanw pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
    435  1.1.2.1  nathanw {
    436  1.1.2.1  nathanw #ifdef ERRORCHECK
    437  1.1.2.1  nathanw 	if ((attr == NULL) ||
    438  1.1.2.1  nathanw 	    (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC))
    439  1.1.2.1  nathanw 		return EINVAL;
    440  1.1.2.1  nathanw #endif
    441  1.1.2.1  nathanw 	attr->ptra_magic = _PT_RWLOCKATTR_DEAD;
    442  1.1.2.1  nathanw 
    443  1.1.2.1  nathanw 	return 0;
    444  1.1.2.1  nathanw }
    445