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