Home | History | Annotate | Line # | Download | only in libpthread
pthread_rwlock.c revision 1.20
      1  1.20       ad /*	$NetBSD: pthread_rwlock.c,v 1.20 2007/08/16 13:54:17 ad Exp $ */
      2   1.2  thorpej 
      3   1.2  thorpej /*-
      4  1.16       ad  * Copyright (c) 2002, 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.17       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.5    lukem #include <sys/cdefs.h>
     40  1.20       ad __RCSID("$NetBSD: pthread_rwlock.c,v 1.20 2007/08/16 13:54:17 ad Exp $");
     41   1.5    lukem 
     42   1.2  thorpej #include <errno.h>
     43   1.2  thorpej 
     44   1.2  thorpej #include "pthread.h"
     45   1.2  thorpej #include "pthread_int.h"
     46   1.2  thorpej 
     47   1.2  thorpej __strong_alias(__libc_rwlock_init,pthread_rwlock_init)
     48   1.2  thorpej __strong_alias(__libc_rwlock_rdlock,pthread_rwlock_rdlock)
     49   1.2  thorpej __strong_alias(__libc_rwlock_wrlock,pthread_rwlock_wrlock)
     50   1.2  thorpej __strong_alias(__libc_rwlock_tryrdlock,pthread_rwlock_tryrdlock)
     51   1.2  thorpej __strong_alias(__libc_rwlock_trywrlock,pthread_rwlock_trywrlock)
     52   1.2  thorpej __strong_alias(__libc_rwlock_unlock,pthread_rwlock_unlock)
     53   1.2  thorpej __strong_alias(__libc_rwlock_destroy,pthread_rwlock_destroy)
     54   1.2  thorpej 
     55   1.2  thorpej int
     56   1.2  thorpej pthread_rwlock_init(pthread_rwlock_t *rwlock,
     57   1.2  thorpej 	    const pthread_rwlockattr_t *attr)
     58   1.2  thorpej {
     59   1.2  thorpej #ifdef ERRORCHECK
     60   1.2  thorpej 	if ((rwlock == NULL) ||
     61   1.2  thorpej 	    (attr && (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC)))
     62   1.2  thorpej 		return EINVAL;
     63   1.2  thorpej #endif
     64   1.2  thorpej 	rwlock->ptr_magic = _PT_RWLOCK_MAGIC;
     65   1.2  thorpej 	pthread_lockinit(&rwlock->ptr_interlock);
     66   1.2  thorpej 	PTQ_INIT(&rwlock->ptr_rblocked);
     67   1.2  thorpej 	PTQ_INIT(&rwlock->ptr_wblocked);
     68   1.2  thorpej 	rwlock->ptr_nreaders = 0;
     69   1.2  thorpej 	rwlock->ptr_writer = NULL;
     70   1.2  thorpej 
     71   1.2  thorpej 	return 0;
     72   1.2  thorpej }
     73   1.2  thorpej 
     74   1.2  thorpej 
     75   1.2  thorpej int
     76   1.2  thorpej pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
     77   1.2  thorpej {
     78   1.2  thorpej #ifdef ERRORCHECK
     79   1.2  thorpej 	if ((rwlock == NULL) ||
     80   1.2  thorpej 	    (rwlock->ptr_magic != _PT_RWLOCK_MAGIC) ||
     81   1.2  thorpej 	    (!PTQ_EMPTY(&rwlock->ptr_rblocked)) ||
     82   1.2  thorpej 	    (!PTQ_EMPTY(&rwlock->ptr_wblocked)) ||
     83   1.2  thorpej 	    (rwlock->ptr_nreaders != 0) ||
     84   1.2  thorpej 	    (rwlock->ptr_writer != NULL))
     85   1.2  thorpej 		return EINVAL;
     86   1.2  thorpej #endif
     87   1.2  thorpej 	rwlock->ptr_magic = _PT_RWLOCK_DEAD;
     88   1.2  thorpej 
     89   1.2  thorpej 	return 0;
     90   1.2  thorpej }
     91   1.2  thorpej 
     92   1.2  thorpej 
     93   1.2  thorpej int
     94   1.2  thorpej pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
     95   1.2  thorpej {
     96   1.2  thorpej 	pthread_t self;
     97   1.2  thorpej #ifdef ERRORCHECK
     98   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
     99   1.2  thorpej 		return EINVAL;
    100   1.2  thorpej #endif
    101   1.2  thorpej 	self = pthread__self();
    102   1.2  thorpej 
    103  1.20       ad 	pthread_spinlock(&rwlock->ptr_interlock);
    104   1.2  thorpej #ifdef ERRORCHECK
    105   1.2  thorpej 	if (rwlock->ptr_writer == self) {
    106  1.20       ad 		pthread_spinunlock(&rwlock->ptr_interlock);
    107   1.2  thorpej 		return EDEADLK;
    108   1.2  thorpej 	}
    109   1.2  thorpej #endif
    110   1.2  thorpej 	/*
    111   1.2  thorpej 	 * Don't get a readlock if there is a writer or if there are waiting
    112   1.2  thorpej 	 * writers; i.e. prefer writers to readers. This strategy is dictated
    113   1.2  thorpej 	 * by SUSv3.
    114   1.2  thorpej 	 */
    115   1.2  thorpej 	while ((rwlock->ptr_writer != NULL) ||
    116   1.2  thorpej 	    (!PTQ_EMPTY(&rwlock->ptr_wblocked))) {
    117  1.17       ad 	    	PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
    118  1.17       ad 		self->pt_sleeponq = 1;
    119  1.17       ad 		self->pt_sleepobj = &rwlock->ptr_rblocked;
    120  1.20       ad 		pthread_spinunlock(&rwlock->ptr_interlock);
    121  1.15       ad 		(void)pthread__park(self, &rwlock->ptr_interlock,
    122  1.18       ad 		    &rwlock->ptr_rblocked, NULL, 0, &rwlock->ptr_rblocked);
    123  1.20       ad 		pthread_spinlock(&rwlock->ptr_interlock);
    124   1.2  thorpej 	}
    125   1.2  thorpej 
    126   1.2  thorpej 	rwlock->ptr_nreaders++;
    127  1.20       ad 	pthread_spinunlock(&rwlock->ptr_interlock);
    128   1.2  thorpej 
    129   1.2  thorpej 	return 0;
    130   1.2  thorpej }
    131   1.2  thorpej 
    132   1.2  thorpej 
    133   1.2  thorpej int
    134   1.2  thorpej pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
    135   1.2  thorpej {
    136  1.20       ad 
    137   1.2  thorpej #ifdef ERRORCHECK
    138   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    139   1.2  thorpej 		return EINVAL;
    140   1.2  thorpej #endif
    141   1.2  thorpej 
    142  1.20       ad 	pthread_spinlock(&rwlock->ptr_interlock);
    143   1.2  thorpej 	/*
    144   1.2  thorpej 	 * Don't get a readlock if there is a writer or if there are waiting
    145   1.2  thorpej 	 * writers; i.e. prefer writers to readers. This strategy is dictated
    146   1.2  thorpej 	 * by SUSv3.
    147   1.2  thorpej 	 */
    148   1.2  thorpej 	if ((rwlock->ptr_writer != NULL) ||
    149   1.2  thorpej 	    (!PTQ_EMPTY(&rwlock->ptr_wblocked))) {
    150  1.20       ad 		pthread_spinunlock(&rwlock->ptr_interlock);
    151   1.2  thorpej 		return EBUSY;
    152   1.2  thorpej 	}
    153   1.2  thorpej 
    154   1.2  thorpej 	rwlock->ptr_nreaders++;
    155  1.20       ad 	pthread_spinunlock(&rwlock->ptr_interlock);
    156   1.2  thorpej 
    157   1.2  thorpej 	return 0;
    158   1.2  thorpej }
    159   1.2  thorpej 
    160   1.2  thorpej 
    161   1.2  thorpej int
    162   1.2  thorpej pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
    163   1.2  thorpej {
    164   1.2  thorpej 	pthread_t self;
    165  1.13      chs 	extern int pthread__started;
    166  1.13      chs 
    167   1.2  thorpej #ifdef ERRORCHECK
    168   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    169   1.2  thorpej 		return EINVAL;
    170   1.2  thorpej #endif
    171   1.2  thorpej 	self = pthread__self();
    172   1.2  thorpej 
    173  1.20       ad 	pthread_spinlock(&rwlock->ptr_interlock);
    174   1.7       cl #ifdef ERRORCHECK
    175   1.7       cl 	if (rwlock->ptr_writer == self) {
    176  1.20       ad 		pthread_spinunlock(&rwlock->ptr_interlock);
    177   1.7       cl 		return EDEADLK;
    178   1.7       cl 	}
    179   1.7       cl #endif
    180   1.2  thorpej 	/*
    181   1.2  thorpej 	 * Prefer writers to readers here; permit writers even if there are
    182   1.2  thorpej 	 * waiting readers.
    183   1.2  thorpej 	 */
    184   1.2  thorpej 	while ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
    185  1.13      chs #ifdef ERRORCHECK
    186  1.13      chs 		if (pthread__started == 0) {
    187  1.20       ad 			pthread_spinunlock(&rwlock->ptr_interlock);
    188  1.13      chs 			return EDEADLK;
    189  1.13      chs 		}
    190  1.13      chs #endif
    191  1.17       ad 	    	PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
    192  1.17       ad 		self->pt_sleeponq = 1;
    193  1.17       ad 		self->pt_sleepobj = &rwlock->ptr_wblocked;
    194  1.20       ad 		pthread_spinunlock(&rwlock->ptr_interlock);
    195  1.15       ad 		(void)pthread__park(self, &rwlock->ptr_interlock,
    196  1.18       ad 		    &rwlock->ptr_wblocked, NULL, 0, &rwlock->ptr_wblocked);
    197  1.20       ad 		pthread_spinlock(&rwlock->ptr_interlock);
    198   1.2  thorpej 	}
    199   1.2  thorpej 
    200   1.2  thorpej 	rwlock->ptr_writer = self;
    201  1.20       ad 	pthread_spinunlock(&rwlock->ptr_interlock);
    202   1.2  thorpej 
    203   1.2  thorpej 	return 0;
    204   1.2  thorpej }
    205   1.2  thorpej 
    206   1.2  thorpej 
    207   1.2  thorpej int
    208   1.2  thorpej pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
    209   1.2  thorpej {
    210   1.2  thorpej 	pthread_t self;
    211   1.2  thorpej #ifdef ERRORCHECK
    212   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    213   1.2  thorpej 		return EINVAL;
    214   1.2  thorpej #endif
    215   1.2  thorpej 	self = pthread__self();
    216   1.2  thorpej 
    217  1.20       ad 	pthread_spinlock(&rwlock->ptr_interlock);
    218   1.2  thorpej 	/*
    219   1.2  thorpej 	 * Prefer writers to readers here; permit writers even if there are
    220   1.2  thorpej 	 * waiting readers.
    221   1.2  thorpej 	 */
    222   1.2  thorpej 	if ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
    223  1.20       ad 		pthread_spinunlock(&rwlock->ptr_interlock);
    224   1.2  thorpej 		return EBUSY;
    225   1.2  thorpej 	}
    226   1.2  thorpej 
    227   1.2  thorpej 	rwlock->ptr_writer = self;
    228  1.20       ad 	pthread_spinunlock(&rwlock->ptr_interlock);
    229   1.2  thorpej 
    230   1.2  thorpej 	return 0;
    231   1.2  thorpej }
    232   1.2  thorpej 
    233   1.2  thorpej 
    234   1.2  thorpej int
    235   1.2  thorpej pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
    236   1.2  thorpej 	    const struct timespec *abs_timeout)
    237   1.2  thorpej {
    238   1.2  thorpej 	pthread_t self;
    239   1.2  thorpej 	int retval;
    240  1.12      chs 
    241   1.2  thorpej #ifdef ERRORCHECK
    242   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    243   1.2  thorpej 		return EINVAL;
    244  1.10  nathanw 	if (abs_timeout == NULL)
    245   1.2  thorpej 		return EINVAL;
    246   1.2  thorpej #endif
    247  1.10  nathanw 	if ((abs_timeout->tv_nsec >= 1000000000) ||
    248  1.10  nathanw 	    (abs_timeout->tv_nsec < 0) ||
    249  1.10  nathanw 	    (abs_timeout->tv_sec < 0))
    250  1.10  nathanw 		return EINVAL;
    251  1.12      chs 
    252   1.2  thorpej 	self = pthread__self();
    253  1.20       ad 	pthread_spinlock(&rwlock->ptr_interlock);
    254   1.2  thorpej #ifdef ERRORCHECK
    255   1.2  thorpej 	if (rwlock->ptr_writer == self) {
    256  1.20       ad 		pthread_spinunlock(&rwlock->ptr_interlock);
    257   1.2  thorpej 		return EDEADLK;
    258   1.2  thorpej 	}
    259   1.2  thorpej #endif
    260   1.2  thorpej 	/*
    261   1.2  thorpej 	 * Don't get a readlock if there is a writer or if there are waiting
    262   1.2  thorpej 	 * writers; i.e. prefer writers to readers. This strategy is dictated
    263   1.2  thorpej 	 * by SUSv3.
    264   1.2  thorpej 	 */
    265   1.2  thorpej 	retval = 0;
    266   1.2  thorpej 	while ((retval == 0) && ((rwlock->ptr_writer != NULL) ||
    267   1.2  thorpej 	    (!PTQ_EMPTY(&rwlock->ptr_wblocked)))) {
    268  1.17       ad 	    	PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
    269  1.17       ad 		self->pt_sleeponq = 1;
    270  1.17       ad 		self->pt_sleepobj = &rwlock->ptr_rblocked;
    271  1.20       ad 		pthread_spinunlock(&rwlock->ptr_interlock);
    272  1.15       ad 		retval = pthread__park(self, &rwlock->ptr_interlock,
    273  1.18       ad 		    &rwlock->ptr_rblocked, abs_timeout, 0,
    274  1.18       ad 		    &rwlock->ptr_rblocked);
    275  1.20       ad 		pthread_spinlock(&rwlock->ptr_interlock);
    276   1.2  thorpej 	}
    277   1.2  thorpej 
    278  1.11  nathanw 	/* One last chance to get the lock, in case it was released between
    279  1.11  nathanw 	   the alarm firing and when this thread got rescheduled, or in case
    280  1.11  nathanw 	   a signal handler kept it busy */
    281  1.11  nathanw 	if ((rwlock->ptr_writer == NULL) &&
    282  1.11  nathanw 	    (PTQ_EMPTY(&rwlock->ptr_wblocked))) {
    283   1.2  thorpej 		rwlock->ptr_nreaders++;
    284  1.11  nathanw 		retval = 0;
    285  1.11  nathanw 	}
    286  1.20       ad 	pthread_spinunlock(&rwlock->ptr_interlock);
    287   1.2  thorpej 
    288   1.2  thorpej 	return retval;
    289   1.2  thorpej }
    290   1.2  thorpej 
    291   1.2  thorpej 
    292   1.2  thorpej int
    293   1.2  thorpej pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock,
    294   1.2  thorpej 	    const struct timespec *abs_timeout)
    295   1.2  thorpej {
    296  1.12      chs 	pthread_t self;
    297   1.2  thorpej 	int retval;
    298  1.12      chs 	extern int pthread__started;
    299  1.12      chs 
    300   1.2  thorpej #ifdef ERRORCHECK
    301   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    302   1.2  thorpej 		return EINVAL;
    303  1.10  nathanw 	if (abs_timeout == NULL)
    304  1.10  nathanw 		return EINVAL;
    305   1.2  thorpej #endif
    306  1.10  nathanw 	if ((abs_timeout->tv_nsec >= 1000000000) ||
    307  1.10  nathanw 	    (abs_timeout->tv_nsec < 0) ||
    308  1.10  nathanw 	    (abs_timeout->tv_sec < 0))
    309  1.10  nathanw 		return EINVAL;
    310  1.12      chs 
    311   1.2  thorpej 	self = pthread__self();
    312  1.20       ad 	pthread_spinlock(&rwlock->ptr_interlock);
    313   1.7       cl #ifdef ERRORCHECK
    314   1.7       cl 	if (rwlock->ptr_writer == self) {
    315  1.20       ad 		pthread_spinunlock(&rwlock->ptr_interlock);
    316   1.7       cl 		return EDEADLK;
    317   1.7       cl 	}
    318   1.7       cl #endif
    319   1.2  thorpej 	/*
    320   1.2  thorpej 	 * Prefer writers to readers here; permit writers even if there are
    321   1.2  thorpej 	 * waiting readers.
    322   1.2  thorpej 	 */
    323   1.2  thorpej 	retval = 0;
    324   1.2  thorpej 	while (retval == 0 &&
    325   1.2  thorpej 	    ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL))) {
    326  1.13      chs #ifdef ERRORCHECK
    327  1.13      chs 		if (pthread__started == 0) {
    328  1.20       ad 			pthread_spinunlock(&rwlock->ptr_interlock);
    329  1.13      chs 			return EDEADLK;
    330  1.13      chs 		}
    331  1.13      chs #endif
    332  1.17       ad 	    	PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
    333  1.17       ad 		self->pt_sleeponq = 1;
    334  1.17       ad 		self->pt_sleepobj = &rwlock->ptr_wblocked;
    335  1.20       ad 		pthread_spinunlock(&rwlock->ptr_interlock);
    336  1.15       ad 		retval = pthread__park(self, &rwlock->ptr_interlock,
    337  1.18       ad 		    &rwlock->ptr_wblocked, abs_timeout, 0,
    338  1.18       ad 		    &rwlock->ptr_wblocked);
    339  1.20       ad 		pthread_spinlock(&rwlock->ptr_interlock);
    340   1.2  thorpej 	}
    341   1.2  thorpej 
    342  1.11  nathanw 	if ((rwlock->ptr_nreaders == 0) && (rwlock->ptr_writer == NULL)) {
    343   1.2  thorpej 		rwlock->ptr_writer = self;
    344  1.11  nathanw 		retval = 0;
    345  1.11  nathanw 	}
    346  1.20       ad 	pthread_spinunlock(&rwlock->ptr_interlock);
    347   1.2  thorpej 
    348   1.8     yamt 	return retval;
    349   1.2  thorpej }
    350   1.2  thorpej 
    351   1.2  thorpej 
    352   1.2  thorpej int
    353   1.2  thorpej pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
    354   1.2  thorpej {
    355   1.3  nathanw 	pthread_t self, writer;
    356   1.2  thorpej #ifdef ERRORCHECK
    357   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    358   1.2  thorpej 		return EINVAL;
    359   1.2  thorpej #endif
    360   1.2  thorpej 	writer = NULL;
    361   1.2  thorpej 	self = pthread__self();
    362   1.2  thorpej 
    363  1.20       ad 	pthread_spinlock(&rwlock->ptr_interlock);
    364   1.2  thorpej 	if (rwlock->ptr_writer != NULL) {
    365   1.2  thorpej 		/* Releasing a write lock. */
    366   1.2  thorpej #ifdef ERRORCHECK
    367   1.2  thorpej 		if (rwlock->ptr_writer != self) {
    368  1.20       ad 			pthread_spinunlock(&rwlock->ptr_interlock);
    369   1.2  thorpej 			return EPERM;
    370   1.2  thorpej 		}
    371   1.2  thorpej #endif
    372   1.2  thorpej 		rwlock->ptr_writer = NULL;
    373   1.2  thorpej 		writer = PTQ_FIRST(&rwlock->ptr_wblocked);
    374   1.2  thorpej 		if (writer != NULL) {
    375   1.2  thorpej 			PTQ_REMOVE(&rwlock->ptr_wblocked, writer, pt_sleep);
    376   1.2  thorpej 		}
    377   1.7       cl 	} else
    378   1.7       cl #ifdef ERRORCHECK
    379   1.7       cl 	if (rwlock->ptr_nreaders > 0)
    380   1.7       cl #endif
    381   1.7       cl 	{
    382   1.2  thorpej 		/* Releasing a read lock. */
    383   1.2  thorpej 		rwlock->ptr_nreaders--;
    384   1.2  thorpej 		if (rwlock->ptr_nreaders == 0) {
    385   1.2  thorpej 			writer = PTQ_FIRST(&rwlock->ptr_wblocked);
    386   1.2  thorpej 			if (writer != NULL)
    387   1.2  thorpej 				PTQ_REMOVE(&rwlock->ptr_wblocked, writer,
    388   1.2  thorpej 				    pt_sleep);
    389   1.2  thorpej 		}
    390   1.7       cl #ifdef ERRORCHECK
    391   1.7       cl 	} else {
    392  1.20       ad 		pthread_spinunlock(&rwlock->ptr_interlock);
    393   1.7       cl 		return EPERM;
    394   1.7       cl #endif
    395   1.2  thorpej 	}
    396   1.2  thorpej 
    397  1.14       ad 	if (writer != NULL)
    398  1.17       ad 		pthread__unpark(self, &rwlock->ptr_interlock,
    399  1.17       ad 		    &rwlock->ptr_wblocked, writer);
    400  1.14       ad 	else
    401  1.17       ad 		pthread__unpark_all(self, &rwlock->ptr_interlock,
    402  1.15       ad 		    &rwlock->ptr_rblocked);
    403   1.6       cl 
    404   1.2  thorpej 	return 0;
    405   1.2  thorpej }
    406   1.2  thorpej 
    407   1.2  thorpej 
    408   1.2  thorpej int
    409   1.2  thorpej pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
    410   1.2  thorpej {
    411   1.2  thorpej #ifdef ERRORCHECK
    412   1.2  thorpej 	if (attr == NULL)
    413   1.2  thorpej 		return EINVAL;
    414   1.2  thorpej #endif
    415   1.2  thorpej 	attr->ptra_magic = _PT_RWLOCKATTR_MAGIC;
    416   1.2  thorpej 
    417   1.2  thorpej 	return 0;
    418   1.2  thorpej }
    419   1.2  thorpej 
    420   1.2  thorpej 
    421   1.2  thorpej int
    422   1.2  thorpej pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
    423   1.2  thorpej {
    424   1.2  thorpej #ifdef ERRORCHECK
    425   1.2  thorpej 	if ((attr == NULL) ||
    426   1.2  thorpej 	    (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC))
    427   1.2  thorpej 		return EINVAL;
    428   1.2  thorpej #endif
    429   1.2  thorpej 	attr->ptra_magic = _PT_RWLOCKATTR_DEAD;
    430   1.2  thorpej 
    431   1.2  thorpej 	return 0;
    432   1.2  thorpej }
    433