Home | History | Annotate | Line # | Download | only in libpthread
pthread_rwlock.c revision 1.15
      1  1.15       ad /*	$NetBSD: pthread_rwlock.c,v 1.15 2006/12/24 18:39:46 ad Exp $ */
      2   1.2  thorpej 
      3   1.2  thorpej /*-
      4   1.2  thorpej  * Copyright (c) 2002 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.2  thorpej  * by Nathan J. Williams.
      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.15       ad __RCSID("$NetBSD: pthread_rwlock.c,v 1.15 2006/12/24 18:39:46 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.14       ad #ifdef PTHREAD_SA
     48   1.2  thorpej static void pthread_rwlock__callback(void *);
     49  1.14       ad #endif
     50   1.2  thorpej 
     51   1.2  thorpej __strong_alias(__libc_rwlock_init,pthread_rwlock_init)
     52   1.2  thorpej __strong_alias(__libc_rwlock_rdlock,pthread_rwlock_rdlock)
     53   1.2  thorpej __strong_alias(__libc_rwlock_wrlock,pthread_rwlock_wrlock)
     54   1.2  thorpej __strong_alias(__libc_rwlock_tryrdlock,pthread_rwlock_tryrdlock)
     55   1.2  thorpej __strong_alias(__libc_rwlock_trywrlock,pthread_rwlock_trywrlock)
     56   1.2  thorpej __strong_alias(__libc_rwlock_unlock,pthread_rwlock_unlock)
     57   1.2  thorpej __strong_alias(__libc_rwlock_destroy,pthread_rwlock_destroy)
     58   1.2  thorpej 
     59   1.2  thorpej int
     60   1.2  thorpej pthread_rwlock_init(pthread_rwlock_t *rwlock,
     61   1.2  thorpej 	    const pthread_rwlockattr_t *attr)
     62   1.2  thorpej {
     63   1.2  thorpej #ifdef ERRORCHECK
     64   1.2  thorpej 	if ((rwlock == NULL) ||
     65   1.2  thorpej 	    (attr && (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC)))
     66   1.2  thorpej 		return EINVAL;
     67   1.2  thorpej #endif
     68   1.2  thorpej 	rwlock->ptr_magic = _PT_RWLOCK_MAGIC;
     69   1.2  thorpej 	pthread_lockinit(&rwlock->ptr_interlock);
     70   1.2  thorpej 	PTQ_INIT(&rwlock->ptr_rblocked);
     71   1.2  thorpej 	PTQ_INIT(&rwlock->ptr_wblocked);
     72   1.2  thorpej 	rwlock->ptr_nreaders = 0;
     73   1.2  thorpej 	rwlock->ptr_writer = NULL;
     74   1.2  thorpej 
     75   1.2  thorpej 	return 0;
     76   1.2  thorpej }
     77   1.2  thorpej 
     78   1.2  thorpej 
     79   1.2  thorpej int
     80   1.2  thorpej pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
     81   1.2  thorpej {
     82   1.2  thorpej #ifdef ERRORCHECK
     83   1.2  thorpej 	if ((rwlock == NULL) ||
     84   1.2  thorpej 	    (rwlock->ptr_magic != _PT_RWLOCK_MAGIC) ||
     85   1.2  thorpej 	    (!PTQ_EMPTY(&rwlock->ptr_rblocked)) ||
     86   1.2  thorpej 	    (!PTQ_EMPTY(&rwlock->ptr_wblocked)) ||
     87   1.2  thorpej 	    (rwlock->ptr_nreaders != 0) ||
     88   1.2  thorpej 	    (rwlock->ptr_writer != NULL))
     89   1.2  thorpej 		return EINVAL;
     90   1.2  thorpej #endif
     91   1.2  thorpej 	rwlock->ptr_magic = _PT_RWLOCK_DEAD;
     92   1.2  thorpej 
     93   1.2  thorpej 	return 0;
     94   1.2  thorpej }
     95   1.2  thorpej 
     96   1.2  thorpej 
     97   1.2  thorpej int
     98   1.2  thorpej pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
     99   1.2  thorpej {
    100   1.2  thorpej 	pthread_t self;
    101   1.2  thorpej #ifdef ERRORCHECK
    102   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    103   1.2  thorpej 		return EINVAL;
    104   1.2  thorpej #endif
    105   1.2  thorpej 	self = pthread__self();
    106   1.2  thorpej 
    107   1.2  thorpej 	pthread_spinlock(self, &rwlock->ptr_interlock);
    108   1.2  thorpej #ifdef ERRORCHECK
    109   1.2  thorpej 	if (rwlock->ptr_writer == self) {
    110   1.2  thorpej 		pthread_spinunlock(self, &rwlock->ptr_interlock);
    111   1.2  thorpej 		return EDEADLK;
    112   1.2  thorpej 	}
    113   1.2  thorpej #endif
    114   1.2  thorpej 	/*
    115   1.2  thorpej 	 * Don't get a readlock if there is a writer or if there are waiting
    116   1.2  thorpej 	 * writers; i.e. prefer writers to readers. This strategy is dictated
    117   1.2  thorpej 	 * by SUSv3.
    118   1.2  thorpej 	 */
    119   1.2  thorpej 	while ((rwlock->ptr_writer != NULL) ||
    120   1.2  thorpej 	    (!PTQ_EMPTY(&rwlock->ptr_wblocked))) {
    121  1.14       ad #ifdef PTHREAD_SA
    122   1.2  thorpej 		PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
    123   1.2  thorpej 		/* Locking a rwlock is not a cancellation point; don't check */
    124   1.2  thorpej 		pthread_spinlock(self, &self->pt_statelock);
    125   1.2  thorpej 		self->pt_state = PT_STATE_BLOCKED_QUEUE;
    126   1.2  thorpej 		self->pt_sleepobj = rwlock;
    127   1.2  thorpej 		self->pt_sleepq = &rwlock->ptr_rblocked;
    128   1.2  thorpej 		self->pt_sleeplock = &rwlock->ptr_interlock;
    129   1.2  thorpej 		pthread_spinunlock(self, &self->pt_statelock);
    130   1.2  thorpej 		pthread__block(self, &rwlock->ptr_interlock);
    131   1.2  thorpej 		/* interlock is not held when we return */
    132   1.2  thorpej 		pthread_spinlock(self, &rwlock->ptr_interlock);
    133  1.14       ad #else	/* PTHREAD_SA */
    134  1.15       ad 		(void)pthread__park(self, &rwlock->ptr_interlock,
    135  1.15       ad 		    rwlock, &rwlock->ptr_rblocked, NULL, 1, 0);
    136  1.14       ad #endif	/* PTHREAD_SA */
    137   1.2  thorpej 	}
    138   1.2  thorpej 
    139   1.2  thorpej 	rwlock->ptr_nreaders++;
    140   1.2  thorpej 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    141   1.2  thorpej 
    142   1.2  thorpej 	return 0;
    143   1.2  thorpej }
    144   1.2  thorpej 
    145   1.2  thorpej 
    146   1.2  thorpej int
    147   1.2  thorpej pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
    148   1.2  thorpej {
    149   1.2  thorpej 	pthread_t self;
    150   1.2  thorpej #ifdef ERRORCHECK
    151   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    152   1.2  thorpej 		return EINVAL;
    153   1.2  thorpej #endif
    154   1.2  thorpej 	self = pthread__self();
    155   1.2  thorpej 
    156   1.2  thorpej 	pthread_spinlock(self, &rwlock->ptr_interlock);
    157   1.2  thorpej 	/*
    158   1.2  thorpej 	 * Don't get a readlock if there is a writer or if there are waiting
    159   1.2  thorpej 	 * writers; i.e. prefer writers to readers. This strategy is dictated
    160   1.2  thorpej 	 * by SUSv3.
    161   1.2  thorpej 	 */
    162   1.2  thorpej 	if ((rwlock->ptr_writer != NULL) ||
    163   1.2  thorpej 	    (!PTQ_EMPTY(&rwlock->ptr_wblocked))) {
    164   1.2  thorpej 		pthread_spinunlock(self, &rwlock->ptr_interlock);
    165   1.2  thorpej 		return EBUSY;
    166   1.2  thorpej 	}
    167   1.2  thorpej 
    168   1.2  thorpej 	rwlock->ptr_nreaders++;
    169   1.2  thorpej 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    170   1.2  thorpej 
    171   1.2  thorpej 	return 0;
    172   1.2  thorpej }
    173   1.2  thorpej 
    174   1.2  thorpej 
    175   1.2  thorpej int
    176   1.2  thorpej pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
    177   1.2  thorpej {
    178   1.2  thorpej 	pthread_t self;
    179  1.13      chs 	extern int pthread__started;
    180  1.13      chs 
    181   1.2  thorpej #ifdef ERRORCHECK
    182   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    183   1.2  thorpej 		return EINVAL;
    184   1.2  thorpej #endif
    185   1.2  thorpej 	self = pthread__self();
    186   1.2  thorpej 
    187   1.2  thorpej 	pthread_spinlock(self, &rwlock->ptr_interlock);
    188   1.7       cl #ifdef ERRORCHECK
    189   1.7       cl 	if (rwlock->ptr_writer == self) {
    190   1.7       cl 		pthread_spinunlock(self, &rwlock->ptr_interlock);
    191   1.7       cl 		return EDEADLK;
    192   1.7       cl 	}
    193   1.7       cl #endif
    194   1.2  thorpej 	/*
    195   1.2  thorpej 	 * Prefer writers to readers here; permit writers even if there are
    196   1.2  thorpej 	 * waiting readers.
    197   1.2  thorpej 	 */
    198   1.2  thorpej 	while ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
    199  1.13      chs #ifdef ERRORCHECK
    200  1.13      chs 		if (pthread__started == 0) {
    201  1.13      chs 			pthread_spinunlock(self, &rwlock->ptr_interlock);
    202  1.13      chs 			return EDEADLK;
    203  1.13      chs 		}
    204  1.13      chs #endif
    205  1.14       ad #ifdef PTHREAD_SA
    206   1.2  thorpej 		PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
    207   1.2  thorpej 		/* Locking a rwlock is not a cancellation point; don't check */
    208   1.2  thorpej 		pthread_spinlock(self, &self->pt_statelock);
    209   1.2  thorpej 		self->pt_state = PT_STATE_BLOCKED_QUEUE;
    210   1.2  thorpej 		self->pt_sleepobj = rwlock;
    211   1.2  thorpej 		self->pt_sleepq = &rwlock->ptr_wblocked;
    212   1.2  thorpej 		self->pt_sleeplock = &rwlock->ptr_interlock;
    213   1.2  thorpej 		pthread_spinunlock(self, &self->pt_statelock);
    214   1.2  thorpej 		pthread__block(self, &rwlock->ptr_interlock);
    215   1.2  thorpej 		/* interlock is not held when we return */
    216   1.2  thorpej 		pthread_spinlock(self, &rwlock->ptr_interlock);
    217  1.14       ad #else
    218  1.15       ad 		(void)pthread__park(self, &rwlock->ptr_interlock,
    219  1.15       ad 		    rwlock, &rwlock->ptr_wblocked, NULL, 1, 0);
    220  1.14       ad #endif
    221   1.2  thorpej 	}
    222   1.2  thorpej 
    223   1.2  thorpej 	rwlock->ptr_writer = self;
    224   1.2  thorpej 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    225   1.2  thorpej 
    226   1.2  thorpej 	return 0;
    227   1.2  thorpej }
    228   1.2  thorpej 
    229   1.2  thorpej 
    230   1.2  thorpej int
    231   1.2  thorpej pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
    232   1.2  thorpej {
    233   1.2  thorpej 	pthread_t self;
    234   1.2  thorpej #ifdef ERRORCHECK
    235   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    236   1.2  thorpej 		return EINVAL;
    237   1.2  thorpej #endif
    238   1.2  thorpej 	self = pthread__self();
    239   1.2  thorpej 
    240   1.2  thorpej 	pthread_spinlock(self, &rwlock->ptr_interlock);
    241   1.2  thorpej 	/*
    242   1.2  thorpej 	 * Prefer writers to readers here; permit writers even if there are
    243   1.2  thorpej 	 * waiting readers.
    244   1.2  thorpej 	 */
    245   1.2  thorpej 	if ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL)) {
    246   1.2  thorpej 		pthread_spinunlock(self, &rwlock->ptr_interlock);
    247   1.2  thorpej 		return EBUSY;
    248   1.2  thorpej 	}
    249   1.2  thorpej 
    250   1.2  thorpej 	rwlock->ptr_writer = self;
    251   1.2  thorpej 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    252   1.2  thorpej 
    253   1.2  thorpej 	return 0;
    254   1.2  thorpej }
    255   1.2  thorpej 
    256   1.2  thorpej 
    257   1.2  thorpej struct pthread_rwlock__waitarg {
    258   1.2  thorpej 	pthread_t ptw_thread;
    259   1.2  thorpej 	pthread_rwlock_t *ptw_rwlock;
    260   1.2  thorpej 	struct pthread_queue_t *ptw_queue;
    261   1.2  thorpej };
    262   1.2  thorpej 
    263   1.2  thorpej int
    264   1.2  thorpej pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
    265   1.2  thorpej 	    const struct timespec *abs_timeout)
    266   1.2  thorpej {
    267   1.2  thorpej 	pthread_t self;
    268  1.14       ad #ifdef PTHREAD_SA
    269   1.2  thorpej 	struct pthread_rwlock__waitarg wait;
    270   1.2  thorpej 	struct pt_alarm_t alarm;
    271  1.14       ad #endif
    272   1.2  thorpej 	int retval;
    273  1.12      chs 
    274   1.2  thorpej #ifdef ERRORCHECK
    275   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    276   1.2  thorpej 		return EINVAL;
    277  1.10  nathanw 	if (abs_timeout == NULL)
    278   1.2  thorpej 		return EINVAL;
    279   1.2  thorpej #endif
    280  1.10  nathanw 	if ((abs_timeout->tv_nsec >= 1000000000) ||
    281  1.10  nathanw 	    (abs_timeout->tv_nsec < 0) ||
    282  1.10  nathanw 	    (abs_timeout->tv_sec < 0))
    283  1.10  nathanw 		return EINVAL;
    284  1.12      chs 
    285   1.2  thorpej 	self = pthread__self();
    286   1.2  thorpej 	pthread_spinlock(self, &rwlock->ptr_interlock);
    287   1.2  thorpej #ifdef ERRORCHECK
    288   1.2  thorpej 	if (rwlock->ptr_writer == self) {
    289   1.9     yamt 		pthread_spinunlock(self, &rwlock->ptr_interlock);
    290   1.2  thorpej 		return EDEADLK;
    291   1.2  thorpej 	}
    292   1.2  thorpej #endif
    293   1.2  thorpej 	/*
    294   1.2  thorpej 	 * Don't get a readlock if there is a writer or if there are waiting
    295   1.2  thorpej 	 * writers; i.e. prefer writers to readers. This strategy is dictated
    296   1.2  thorpej 	 * by SUSv3.
    297   1.2  thorpej 	 */
    298   1.2  thorpej 	retval = 0;
    299   1.2  thorpej 	while ((retval == 0) && ((rwlock->ptr_writer != NULL) ||
    300   1.2  thorpej 	    (!PTQ_EMPTY(&rwlock->ptr_wblocked)))) {
    301  1.14       ad #ifdef PTHREAD_SA
    302   1.2  thorpej 		wait.ptw_thread = self;
    303   1.2  thorpej 		wait.ptw_rwlock = rwlock;
    304   1.2  thorpej 		wait.ptw_queue = &rwlock->ptr_rblocked;
    305   1.2  thorpej 		pthread__alarm_add(self, &alarm, abs_timeout,
    306   1.2  thorpej 		    pthread_rwlock__callback, &wait);
    307   1.2  thorpej 		PTQ_INSERT_TAIL(&rwlock->ptr_rblocked, self, pt_sleep);
    308   1.2  thorpej 		/* Locking a rwlock is not a cancellation point; don't check */
    309   1.2  thorpej 		pthread_spinlock(self, &self->pt_statelock);
    310   1.2  thorpej 		self->pt_state = PT_STATE_BLOCKED_QUEUE;
    311   1.2  thorpej 		self->pt_sleepobj = rwlock;
    312   1.2  thorpej 		self->pt_sleepq = &rwlock->ptr_rblocked;
    313   1.2  thorpej 		self->pt_sleeplock = &rwlock->ptr_interlock;
    314   1.2  thorpej 		pthread_spinunlock(self, &self->pt_statelock);
    315   1.2  thorpej 		pthread__block(self, &rwlock->ptr_interlock);
    316   1.2  thorpej 		/* interlock is not held when we return */
    317   1.2  thorpej 		pthread__alarm_del(self, &alarm);
    318   1.2  thorpej 		if (pthread__alarm_fired(&alarm))
    319   1.2  thorpej 			retval = ETIMEDOUT;
    320   1.2  thorpej 		pthread_spinlock(self, &rwlock->ptr_interlock);
    321  1.14       ad #else
    322  1.15       ad 		retval = pthread__park(self, &rwlock->ptr_interlock,
    323  1.15       ad 		    rwlock, &rwlock->ptr_rblocked, abs_timeout, 1, 0);
    324  1.14       ad #endif
    325   1.2  thorpej 	}
    326   1.2  thorpej 
    327  1.11  nathanw 	/* One last chance to get the lock, in case it was released between
    328  1.11  nathanw 	   the alarm firing and when this thread got rescheduled, or in case
    329  1.11  nathanw 	   a signal handler kept it busy */
    330  1.11  nathanw 	if ((rwlock->ptr_writer == NULL) &&
    331  1.11  nathanw 	    (PTQ_EMPTY(&rwlock->ptr_wblocked))) {
    332   1.2  thorpej 		rwlock->ptr_nreaders++;
    333  1.11  nathanw 		retval = 0;
    334  1.11  nathanw 	}
    335   1.2  thorpej 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    336   1.2  thorpej 
    337   1.2  thorpej 	return retval;
    338   1.2  thorpej }
    339   1.2  thorpej 
    340   1.2  thorpej 
    341   1.2  thorpej int
    342   1.2  thorpej pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock,
    343   1.2  thorpej 	    const struct timespec *abs_timeout)
    344   1.2  thorpej {
    345  1.14       ad #ifdef PTHREAD_SA
    346   1.2  thorpej 	struct pthread_rwlock__waitarg wait;
    347   1.2  thorpej 	struct pt_alarm_t alarm;
    348  1.14       ad #endif
    349  1.12      chs 	pthread_t self;
    350   1.2  thorpej 	int retval;
    351  1.12      chs 	extern int pthread__started;
    352  1.12      chs 
    353   1.2  thorpej #ifdef ERRORCHECK
    354   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    355   1.2  thorpej 		return EINVAL;
    356  1.10  nathanw 	if (abs_timeout == NULL)
    357  1.10  nathanw 		return EINVAL;
    358   1.2  thorpej #endif
    359  1.10  nathanw 	if ((abs_timeout->tv_nsec >= 1000000000) ||
    360  1.10  nathanw 	    (abs_timeout->tv_nsec < 0) ||
    361  1.10  nathanw 	    (abs_timeout->tv_sec < 0))
    362  1.10  nathanw 		return EINVAL;
    363  1.12      chs 
    364   1.2  thorpej 	self = pthread__self();
    365   1.2  thorpej 	pthread_spinlock(self, &rwlock->ptr_interlock);
    366   1.7       cl #ifdef ERRORCHECK
    367   1.7       cl 	if (rwlock->ptr_writer == self) {
    368   1.9     yamt 		pthread_spinunlock(self, &rwlock->ptr_interlock);
    369   1.7       cl 		return EDEADLK;
    370   1.7       cl 	}
    371   1.7       cl #endif
    372   1.2  thorpej 	/*
    373   1.2  thorpej 	 * Prefer writers to readers here; permit writers even if there are
    374   1.2  thorpej 	 * waiting readers.
    375   1.2  thorpej 	 */
    376   1.2  thorpej 	retval = 0;
    377   1.2  thorpej 	while (retval == 0 &&
    378   1.2  thorpej 	    ((rwlock->ptr_nreaders > 0) || (rwlock->ptr_writer != NULL))) {
    379  1.13      chs #ifdef ERRORCHECK
    380  1.13      chs 		if (pthread__started == 0) {
    381  1.13      chs 			pthread_spinunlock(self, &rwlock->ptr_interlock);
    382  1.13      chs 			return EDEADLK;
    383  1.13      chs 		}
    384  1.13      chs #endif
    385  1.14       ad #ifdef PTHREAD_SA
    386   1.2  thorpej 		wait.ptw_thread = self;
    387   1.2  thorpej 		wait.ptw_rwlock = rwlock;
    388   1.2  thorpej 		wait.ptw_queue = &rwlock->ptr_wblocked;
    389   1.2  thorpej 		pthread__alarm_add(self, &alarm, abs_timeout,
    390   1.2  thorpej 		    pthread_rwlock__callback, &wait);
    391   1.2  thorpej 		PTQ_INSERT_TAIL(&rwlock->ptr_wblocked, self, pt_sleep);
    392   1.2  thorpej 		/* Locking a rwlock is not a cancellation point; don't check */
    393   1.2  thorpej 		pthread_spinlock(self, &self->pt_statelock);
    394   1.2  thorpej 		self->pt_state = PT_STATE_BLOCKED_QUEUE;
    395   1.2  thorpej 		self->pt_sleepobj = rwlock;
    396   1.2  thorpej 		self->pt_sleepq = &rwlock->ptr_wblocked;
    397   1.2  thorpej 		self->pt_sleeplock = &rwlock->ptr_interlock;
    398   1.2  thorpej 		pthread_spinunlock(self, &self->pt_statelock);
    399   1.2  thorpej 		pthread__block(self, &rwlock->ptr_interlock);
    400   1.2  thorpej 		/* interlock is not held when we return */
    401   1.2  thorpej 		pthread__alarm_del(self, &alarm);
    402   1.2  thorpej 		if (pthread__alarm_fired(&alarm))
    403   1.2  thorpej 			retval = ETIMEDOUT;
    404   1.2  thorpej 		pthread_spinlock(self, &rwlock->ptr_interlock);
    405  1.14       ad #else
    406  1.15       ad 		retval = pthread__park(self, &rwlock->ptr_interlock,
    407  1.15       ad 		    rwlock, &rwlock->ptr_wblocked, abs_timeout, 1, 0);
    408  1.14       ad #endif
    409   1.2  thorpej 	}
    410   1.2  thorpej 
    411  1.11  nathanw 	if ((rwlock->ptr_nreaders == 0) && (rwlock->ptr_writer == NULL)) {
    412   1.2  thorpej 		rwlock->ptr_writer = self;
    413  1.11  nathanw 		retval = 0;
    414  1.11  nathanw 	}
    415   1.2  thorpej 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    416   1.2  thorpej 
    417   1.8     yamt 	return retval;
    418   1.2  thorpej }
    419   1.2  thorpej 
    420   1.2  thorpej 
    421  1.14       ad #ifdef PTHREAD_SA
    422   1.2  thorpej static void
    423   1.2  thorpej pthread_rwlock__callback(void *arg)
    424   1.2  thorpej {
    425   1.2  thorpej 	struct pthread_rwlock__waitarg *a;
    426   1.2  thorpej 	pthread_t self;
    427   1.2  thorpej 
    428   1.2  thorpej 	a = arg;
    429   1.2  thorpej 	self = pthread__self();
    430   1.2  thorpej 
    431   1.2  thorpej 	pthread_spinlock(self, &a->ptw_rwlock->ptr_interlock);
    432   1.2  thorpej 	/*
    433   1.2  thorpej 	 * Don't dequeue and schedule the thread if it's already been
    434   1.2  thorpej 	 * queued up by a signal or broadcast (but hasn't yet run as far
    435   1.2  thorpej 	 * as pthread__alarm_del(), or we wouldn't be here, and hence can't
    436   1.2  thorpej 	 * have become blocked on some *other* queue).
    437   1.2  thorpej 	 */
    438   1.2  thorpej 	if (a->ptw_thread->pt_state == PT_STATE_BLOCKED_QUEUE) {
    439   1.2  thorpej 		PTQ_REMOVE(a->ptw_queue, a->ptw_thread, pt_sleep);
    440   1.2  thorpej 		pthread__sched(self, a->ptw_thread);
    441   1.2  thorpej 	}
    442   1.2  thorpej 	pthread_spinunlock(self, &a->ptw_rwlock->ptr_interlock);
    443   1.2  thorpej 
    444   1.2  thorpej }
    445  1.14       ad #endif
    446   1.2  thorpej 
    447   1.2  thorpej 
    448   1.2  thorpej int
    449   1.2  thorpej pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
    450   1.2  thorpej {
    451   1.3  nathanw 	pthread_t self, writer;
    452  1.15       ad #ifdef PTHREAD_SA
    453   1.2  thorpej 	struct pthread_queue_t blockedq;
    454  1.15       ad 	PTQ_INIT(&blockedq);
    455  1.15       ad #endif
    456   1.2  thorpej #ifdef ERRORCHECK
    457   1.2  thorpej 	if ((rwlock == NULL) || (rwlock->ptr_magic != _PT_RWLOCK_MAGIC))
    458   1.2  thorpej 		return EINVAL;
    459   1.2  thorpej #endif
    460   1.2  thorpej 	writer = NULL;
    461   1.2  thorpej 	self = pthread__self();
    462   1.2  thorpej 
    463   1.2  thorpej 	pthread_spinlock(self, &rwlock->ptr_interlock);
    464   1.2  thorpej 	if (rwlock->ptr_writer != NULL) {
    465   1.2  thorpej 		/* Releasing a write lock. */
    466   1.2  thorpej #ifdef ERRORCHECK
    467   1.2  thorpej 		if (rwlock->ptr_writer != self) {
    468   1.2  thorpej 			pthread_spinunlock(self, &rwlock->ptr_interlock);
    469   1.2  thorpej 			return EPERM;
    470   1.2  thorpej 		}
    471   1.2  thorpej #endif
    472   1.2  thorpej 		rwlock->ptr_writer = NULL;
    473   1.2  thorpej 		writer = PTQ_FIRST(&rwlock->ptr_wblocked);
    474   1.2  thorpej 		if (writer != NULL) {
    475   1.2  thorpej 			PTQ_REMOVE(&rwlock->ptr_wblocked, writer, pt_sleep);
    476   1.2  thorpej 		} else {
    477  1.15       ad #ifdef PTHREAD_SA
    478   1.2  thorpej 			blockedq = rwlock->ptr_rblocked;
    479   1.2  thorpej 			PTQ_INIT(&rwlock->ptr_rblocked);
    480  1.15       ad #endif
    481   1.2  thorpej 		}
    482   1.7       cl 	} else
    483   1.7       cl #ifdef ERRORCHECK
    484   1.7       cl 	if (rwlock->ptr_nreaders > 0)
    485   1.7       cl #endif
    486   1.7       cl 	{
    487   1.2  thorpej 		/* Releasing a read lock. */
    488   1.2  thorpej 		rwlock->ptr_nreaders--;
    489   1.2  thorpej 		if (rwlock->ptr_nreaders == 0) {
    490   1.2  thorpej 			writer = PTQ_FIRST(&rwlock->ptr_wblocked);
    491   1.2  thorpej 			if (writer != NULL)
    492   1.2  thorpej 				PTQ_REMOVE(&rwlock->ptr_wblocked, writer,
    493   1.2  thorpej 				    pt_sleep);
    494   1.2  thorpej 		}
    495   1.7       cl #ifdef ERRORCHECK
    496   1.7       cl 	} else {
    497   1.7       cl 		pthread_spinunlock(self, &rwlock->ptr_interlock);
    498   1.7       cl 		return EPERM;
    499   1.7       cl #endif
    500   1.2  thorpej 	}
    501   1.2  thorpej 
    502  1.14       ad #ifdef PTHREAD_SA
    503   1.2  thorpej 	if (writer != NULL)
    504   1.2  thorpej 		pthread__sched(self, writer);
    505   1.2  thorpej 	else
    506   1.3  nathanw 		pthread__sched_sleepers(self, &blockedq);
    507  1.14       ad 
    508   1.6       cl 	pthread_spinunlock(self, &rwlock->ptr_interlock);
    509  1.14       ad #else	/* PTHREAD_SA */
    510  1.14       ad 	if (writer != NULL)
    511  1.14       ad 		pthread__unpark(self, &rwlock->ptr_interlock, rwlock, writer);
    512  1.14       ad 	else
    513  1.14       ad 		pthread__unpark_all(self, &rwlock->ptr_interlock, rwlock,
    514  1.15       ad 		    &rwlock->ptr_rblocked);
    515  1.14       ad #endif	/* PTHREAD_SA */
    516   1.6       cl 
    517   1.2  thorpej 	return 0;
    518   1.2  thorpej }
    519   1.2  thorpej 
    520   1.2  thorpej 
    521   1.2  thorpej int
    522   1.2  thorpej pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
    523   1.2  thorpej {
    524   1.2  thorpej #ifdef ERRORCHECK
    525   1.2  thorpej 	if (attr == NULL)
    526   1.2  thorpej 		return EINVAL;
    527   1.2  thorpej #endif
    528   1.2  thorpej 	attr->ptra_magic = _PT_RWLOCKATTR_MAGIC;
    529   1.2  thorpej 
    530   1.2  thorpej 	return 0;
    531   1.2  thorpej }
    532   1.2  thorpej 
    533   1.2  thorpej 
    534   1.2  thorpej int
    535   1.2  thorpej pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
    536   1.2  thorpej {
    537   1.2  thorpej #ifdef ERRORCHECK
    538   1.2  thorpej 	if ((attr == NULL) ||
    539   1.2  thorpej 	    (attr->ptra_magic != _PT_RWLOCKATTR_MAGIC))
    540   1.2  thorpej 		return EINVAL;
    541   1.2  thorpej #endif
    542   1.2  thorpej 	attr->ptra_magic = _PT_RWLOCKATTR_DEAD;
    543   1.2  thorpej 
    544   1.2  thorpej 	return 0;
    545   1.2  thorpej }
    546