2 * Copyright (c) 1998 Alex Nash
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $Id: uthread_rwlock.c,v 1.2 1998/09/07 19:23:55 alex Exp $
35 #include "pthread_private.h"
37 /* maximum number of times a read lock may be obtained */
38 #define MAX_READ_LOCKS (INT_MAX - 1)
40 static int init_static (pthread_rwlock_t *rwlock);
42 static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER;
45 init_static (pthread_rwlock_t *rwlock)
49 _SPINLOCK(&static_init_lock);
52 ret = pthread_rwlock_init(rwlock, NULL);
56 _SPINUNLOCK(&static_init_lock);
62 pthread_rwlock_destroy (pthread_rwlock_t *rwlock)
69 pthread_rwlock_t prwlock;
73 pthread_mutex_destroy(&prwlock->lock);
74 pthread_cond_destroy(&prwlock->read_signal);
75 pthread_cond_destroy(&prwlock->write_signal);
87 pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
89 pthread_rwlock_t prwlock;
92 /* allocate rwlock object */
93 prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock));
98 /* initialize the lock */
99 if ((ret = pthread_mutex_init(&prwlock->lock, NULL)) != 0)
102 /* initialize the read condition signal */
103 ret = pthread_cond_init(&prwlock->read_signal, NULL);
106 pthread_mutex_destroy(&prwlock->lock);
109 /* initialize the write condition signal */
110 ret = pthread_cond_init(&prwlock->write_signal, NULL);
113 pthread_cond_destroy(&prwlock->read_signal);
114 pthread_mutex_destroy(&prwlock->lock);
119 prwlock->blocked_writers = 0;
130 pthread_rwlock_rdlock (pthread_rwlock_t *rwlock)
132 pthread_rwlock_t prwlock;
140 /* check for static initialization */
141 if (prwlock == NULL) {
142 if ((ret = init_static(rwlock)) != 0)
148 /* grab the monitor lock */
149 if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0)
152 /* give writers priority over readers */
153 while (prwlock->blocked_writers || prwlock->state < 0) {
154 ret = pthread_cond_wait(&prwlock->read_signal, &prwlock->lock);
157 /* can't do a whole lot if this fails */
158 pthread_mutex_unlock(&prwlock->lock);
163 /* check lock count */
164 if (prwlock->state == MAX_READ_LOCKS)
167 ++prwlock->state; /* indicate we are locked for reading */
170 * Something is really wrong if this call fails. Returning
171 * error won't do because we've already obtained the read
172 * lock. Decrementing 'state' is no good because we probably
173 * don't have the monitor lock.
175 pthread_mutex_unlock(&prwlock->lock);
181 pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock)
183 pthread_rwlock_t prwlock;
191 /* check for static initialization */
192 if (prwlock == NULL) {
193 if ((ret = init_static(rwlock)) != 0)
199 /* grab the monitor lock */
200 if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0)
203 /* give writers priority over readers */
204 if (prwlock->blocked_writers || prwlock->state < 0)
206 else if (prwlock->state == MAX_READ_LOCKS)
207 ret = EAGAIN; /* too many read locks acquired */
209 ++prwlock->state; /* indicate we are locked for reading */
211 /* see the comment on this in pthread_rwlock_rdlock */
212 pthread_mutex_unlock(&prwlock->lock);
218 pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock)
220 pthread_rwlock_t prwlock;
228 /* check for static initialization */
229 if (prwlock == NULL) {
230 if ((ret = init_static(rwlock)) != 0)
236 /* grab the monitor lock */
237 if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0)
240 if (prwlock->state != 0)
243 /* indicate we are locked for writing */
246 /* see the comment on this in pthread_rwlock_rdlock */
247 pthread_mutex_unlock(&prwlock->lock);
253 pthread_rwlock_unlock (pthread_rwlock_t *rwlock)
255 pthread_rwlock_t prwlock;
266 /* grab the monitor lock */
267 if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0)
270 if (prwlock->state > 0) {
271 if (--prwlock->state == 0 && prwlock->blocked_writers)
272 ret = pthread_cond_signal(&prwlock->write_signal);
273 } else if (prwlock->state < 0) {
276 if (prwlock->blocked_writers)
277 ret = pthread_cond_signal(&prwlock->write_signal);
279 ret = pthread_cond_broadcast(&prwlock->read_signal);
283 /* see the comment on this in pthread_rwlock_rdlock */
284 pthread_mutex_unlock(&prwlock->lock);
290 pthread_rwlock_wrlock (pthread_rwlock_t *rwlock)
292 pthread_rwlock_t prwlock;
300 /* check for static initialization */
301 if (prwlock == NULL) {
302 if ((ret = init_static(rwlock)) != 0)
308 /* grab the monitor lock */
309 if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0)
312 while (prwlock->state != 0) {
313 ++prwlock->blocked_writers;
315 ret = pthread_cond_wait(&prwlock->write_signal, &prwlock->lock);
318 --prwlock->blocked_writers;
319 pthread_mutex_unlock(&prwlock->lock);
323 --prwlock->blocked_writers;
326 /* indicate we are locked for writing */
329 /* see the comment on this in pthread_rwlock_rdlock */
330 pthread_mutex_unlock(&prwlock->lock);
335 #endif /* _THREAD_SAFE */